hareshdgr8 Ответов: 6

Сравните дату с месяцем и годом в SQL server


select * from Performance_tb where format(Perf_Date,'MM/yyyy')='01/2020'


дает отличный результат
но когда я использовал это

select * from Performance_tb where format(Perf_Date,'MM/yyyy')<'01/2020'

- Показывает неверные данные.


МОИ ДАННЫЕ
Perf_Date
--------------------------------
2019-09-11 00:00:00.000
2019-09-12 00:00:00.000
2019-09-14 00:00:00.000
2019-09-15 00:00:00.000
2019-09-16 00:00:00.000
2019-09-17 00:00:00.000
2019-09-18 00:00:00.000
2019-09-19 00:00:00.000
2019-09-20 00:00:00.000
2019-09-21 00:00:00.000
2019-09-22 00:00:00.000
2019-09-23 00:00:00.000
2019-09-24 00:00:00.000
2019-09-25 00:00:00.000
2019-09-26 00:00:00.000
2019-09-27 00:00:00.000
2019-12-19 00:00:00.000
2019-12-20 00:00:00.000
2019-12-22 00:00:00.000
2019-12-23 00:00:00.000
2020-01-03 00:00:00.000
2020-01-04 00:00:00.000
2020-01-06 00:00:00.000
2020-01-07 00:00:00.000
2020-01-08 00:00:00.000
2020-01-09 00:00:00.000
2020-01-31 00:00:00.000
2020-02-01 00:00:00.000
2020-02-06 00:00:00.000
2020-02-07 00:00:00.000
2020-02-08 00:00:00.000
2020-02-17 00:00:00.000
2020-02-25 00:00:00.000
2020-03-01 00:00:00.000
2020-03-02 00:00:00.000

This is my data i want jan month data as well as i want before jan month data both case need to fire same query what can i do sir
my parameter is Month/Year i.e. 01/2020 so i want "=01/2020" or "<01/2020"


Что я уже пробовал:

select * from Performance_tb where format(Perf_Date,'MM/yyyy')<'01/2020'

ZurdoDev

Потому что вы преобразуете дату в строку. Не делай этого.

hareshdgr8

сэр как я могу это сделать если мне нужен тот же код просто нужно изменить меньше чем знак или другое вы можете мне предоставить

ZurdoDev

выберите * из Performance_tb, где Perf_Date < '2020-01-01'

hareshdgr8

сэр я не знаю о дне дате только я получаю значение месяца и года из другого источника

ZurdoDev

Да, но вы же хотите что-нибудь до января 2020 года, верно? Итак, это все, что угодно до 2020-01-01 года. Это одно и то же.

Вы также можете сделать
Выберите * из таблицы someTable, где YEAR(DATE) <= YEAR(@someDate) и MONTH(DATE) < MONTH(@someDate)

Но первый способ, скорее всего, лучше в вашем случае.

hareshdgr8

Получение Неправильного Вывода .. с этим, сэр...

ZurdoDev

Тогда просто исправь это. Не знаю, чего ты от нас хочешь. У вас есть простое требование-найти даты, которые предшествуют другой дате. Я думаю, вы делаете его более сложным.

Я дал вам 2 способа сделать это.

hareshdgr8

у меня есть сэр только месяц и год как я могу это исправить

ZurdoDev

Затем используйте функции MONTH() и YEAR (), которые я уже предложил.

6 Ответов

Рейтинг:
2

Maciej Los

Если вы хотите отказаться от временной части, вы можете использовать:

SELECT CAST(Perf_Date AS DATE) JustDateWithoutTimePart

Если вы хотите отклонить дневную часть, я бы предложил заменить ее предопределенным значением (например, первый день месяца), чтобы иметь возможность сравнивать с другой датой (только месяц и год):
DECLARE @somemonth DATE = CAST('2020-01-01' AS DATE);
SELECT DATEADD(MM, DATEDIFF(MM, 0, Perf_Date), 0) AS MonthAndYearWithPredefinedDay
FROM Performance_tb 
WHERE Perf_Date = @somemonth
--or starting from MS SQL Server 2012
--SELECT DATEADD(DAY,1,EOMONTH(Perf_Date,-1))


[РЕДАКТИРОВАТЬ]
hareshdgr8 написал:

у меня есть только год и месяц, как 2020-01


Это очень плохая практика хранить даты в виде текста! В этом причина нескольких проблем!
Я бы настоятельно рекомендовал вам измениться Perf_Date поле для правильного типа даты.

В этот момент вы можете сделать что-то подобное:
SET DATEFORMAT ymd;

DECLARE @enddate DATE = CAST('2020-01-01' AS DATE)

;WITH SemiDates AS
(
	SELECT '2020-02' SemiDate
	UNION ALL
	SELECT '2020-01' SemiDate
	UNION ALL
	SELECT '2019-10' SemiDate
	UNION ALL
	SELECT '2019-12' SemiDate
	UNION ALL
	SELECT '2018-11' SemiDate
	UNION ALL
	SELECT '2018-05' SemiDate
)
SELECT DATEFROMPARTS(CAST(LEFT(SemiDate, 4) AS INT), CAST(RIGHT(SemiDate, 2) AS INT), 1) As ShortDate
FROM SemiDates 
WHERE DATEFROMPARTS(CAST(LEFT(SemiDate, 4) AS INT), CAST(RIGHT(SemiDate, 2) AS INT), 1) <@enddate


[EDIT2]
Последний шанс...
Взгляните на нижеприведенный запрос:
--create range of dates to this date (today)
DECLARE @enddate DATE = GETDATE();
--filter data based on this date => get data till the end of January
DECLARE @monthyear DATE = '2020-02-01';

--create range of dates
;WITH SetOfDates AS
(
	SELECT CAST('2019-12-20' AS DATE) Perf_Date 
	UNION ALL 
	SELECT DATEADD(DD, 1, Perf_Date) Perf_Date
	FROM SetOfDates
	WHERE DATEADD(DD, 1, Perf_Date) <= @enddate 
)
--get original date and date converted to YYYY-MM-01 format
SELECT Perf_Date, CAST(DATEADD(MM, DATEDIFF(MM, 0, Perf_Date), 0) AS DATE) AS MonthAndYearWithPredefinedDay 
FROM SetOfDates
WHERE DATEADD(MM, DATEDIFF(MM, 0, Perf_Date), 0)< @monthyear;


Эта продукция:
2019-12-20	2019-12-01
2019-12-21	2019-12-01
...
2019-12-31	2019-12-01
2020-01-01	2020-01-01
...
2020-01-31	2020-01-01

а это значит, что весь набор данных будет собран до конца января.
Теперь ты это понимаешь?


hareshdgr8

здесь, Если я хочу получить данные до 2020-01 года, у меня нет даты, сэр, куда я должен передать, потому что я хочу те же данные месяца, а также данные до месяца, также используя один запрос, который я хочу использовать.

Maciej Los

Итак, измените условие where:

WHERE Perf_Date < @somemonth

Попробуй!

hareshdgr8

сэр, вы все еще не понимаете, где я могу передать это значение CAST ('2020-01-01' в качестве даты)
у меня есть только год и месяц, как 2020-01

Maciej Los

ОК. Пожалуйста, подождите, я улучшу свой ответ.

Richard Deeming

DECLARE @YearAndMonth varchar(7) = '2020-01';
DECLARE @MonthStart date = CAST(@YearAndMonth + '-01' As date);

Maciej Los

;)

hareshdgr8

сэр если мне нужны полные месячные данные то это больше не будет работать вот почему я просто передаю только месяц и год а мое поле Perf_Date это datetime datatype

Richard Deeming

Какая часть непонятна?

Вы проходите через год и месяц: '2020-01'.

Вы добавляете '-01' к этому и бросил его в а date чтобы получить первый день этого месяца.

Затем вы используете DateAdd чтобы получить первый день работы следующий месяц и фильтровать записи на основе диапазона дат - Подробнее см. Решение 2.

Какая часть этого "не сработает"?

hareshdgr8

Сэр, если мне нужны полные месячные данные, то, пожалуйста, помогите, вот почему он не работает...

Richard Deeming

Сколько раз мы должны тебе это объяснять?

И что, собственно, делает "не работать" значит?

Maciej Los

Итак, используйте правильный тип данных вместо того, чтобы преобразовывать его в строку! Как я уже говорил, когда вы преобразуете его в текст, у вас будет несколько проблем.

Рейтинг:
1

Richard Deeming

Не форматируйте столбец даты; не преобразуйте столбец даты; и не пытайтесь вызвать функцию в столбце даты. Ничего из этого не будет SARGable[^].

Вместо этого проверьте диапазон дат.

DECLARE @Month date = '20200101';

-- Make sure we've got the first day of the month:
DECLARE @MonthStartInclusive date = DateAdd(day, 1 - Day(@Month), @Month);

-- Find the first day of the following month:
DECLARE @MonthEndExclusive date = DateAdd(month, 1, @MonthStartInclusive);

-- Data within the month:
SELECT * FROM Performance_tb WHERE Perf_Date >= @MonthStartInclusive And Perf_Date < @MonthEndExclusive;

-- Date before the start of the month:
SELECT * FROM Performance_tb WHERE Perf_Date < @MonthStartInclusive;

-- Data after the end of the month:
SELECT * FROM Performance_tb WHERE Perf_Date >= @MonthEndExclusive;


Maciej Los

5ed!

Рейтинг:
1

phil.o

Ты можешь попробовать

SELECT * FROM Performance_tb WHERE YEAR(Perf_Date) < 2020
Или вы можете попробовать отформатировать год/месяц в yyyyMM Это привело бы к допустимому целочисленному представлению, которое сохраняло бы правильный порядок.
SELECT * FROM Performance_tb WHERE CAST(FORMAT(Perf_Date, 'yyyyMM') AS int) < 202001


hareshdgr8

отклонить, так как в компании Google заявили, что никогда не преобразовать поле Дата
https://www.brentozar.com/blitzcache/non-sargable-predicates/

ZurdoDev

Google ошибается. Бывают случаи, когда вам нужно преобразовать поле даты, но, вероятно, не в вашем случае.

hareshdgr8

пожалуйста проверьте мое решение сэр я нашел его в google и применил без проблем получил идеальный результат

ZurdoDev

Итак, вы его преобразуете. Всегда есть миллион способов сделать что-то в развитии. Рад, что вы нашли тот, который работает для вас.

phil.o

И все же предложенное вами решение использует функцию CONVERT. Ответ Ричарда Диминга здесь наиболее уместен.

Рейтинг:
0

Patrice T

Цитата:
Показывает неверные данные.

Вы только забыли сказать, что не так в результате и что ожидается.
Вообще говоря, если вы хотите сравнить даты в виде строк, то следует использовать формат "ггггммдд" или "гггг/ММ/ДД".
Если я понимаю, чего вы хотите, вам нужно использовать "гггг/мм".
select * from Performance_tb where format(Perf_Date,'yyyy/MM')<'2020/01'

Это дает что-нибудь до 2020 года.


hareshdgr8

сэр не получая правильных данных в соответствии с моими он должен дать мне 49 записей и для этого запроса дать мне 20 записей только потому что формат преобразует дату в строку

Patrice T

количество записей не помогает нам понять, что же не так в результате.

Рейтинг:
0

CHill60

В ответ на ОП публикует некоторые фактические данные...

Если это ваши данные то решение 3 является правильный. В этих данных есть только 20 строк, которые находятся до января 2020 года. Если вы хотите включить январь, то используйте <=.

В ответ на это решение вы заявили, что ожидаете возвращения 49 записей, но в данных есть только 35 записей!

Единственное улучшение, которое я бы сделал, - это сделать преобразование в дату вне самого запроса (т. е. только один раз для повышения эффективности), например

declare @parm varchar(8) = '01/2020'
declare @castparm date = CAST('01/' + @parm as DATE) -- results in 01/01/2020

select perf_date from @Performance_tb 
where Perf_Date < @castparm
В других комментариях вы предположили, что этот параметр будет иметь следующий формат 2020-01 Это на самом деле гораздо лучше, чем 01/2020 поскольку это гарантирует, что приведение к дате является однозначным, т. е.
declare @castparm date = CAST(@parm + '-01' as DATE) -- results in 2020-01-01
Как отметили другие члены Совета выше, такие даты, как 01/04/2020, могут быть истолкованы как 4 января или 1 апреля в зависимости от региональных условий, тогда как 2020-04-01-это явно 1 апреля.


hareshdgr8

нет, сэр, при использовании declare @castparm date = CAST(@parm + '-01' as DATE) - результаты в 2020-01-01 это дает мне только 1 дату данных, а не данные целого месяца, такие как данные месяца января

CHill60

Я действительно проверил свой запрос, и он вернул 20 строк, которые я ожидал. Код, который вы мне процитировали, таков: подразумеваемый чтобы вернуть одно значение - вы затем используете это значение для запроса таблицы!

Рейтинг:
0

hareshdgr8

Используя это получите идеальный результат



select * from Performance_tb where convert(VARCHAR(7),Perf_Date,111) < '2020/04'


Maciej Los

Извините, но это неправильно!

hareshdgr8

В противном случае Сэр пожалуйста предложите мне больше решения

Maciej Los

Пожалуйста, смотрите решение № 5

hareshdgr8

никакой сэр от этого не получил результата должным образом..

Maciej Los

Это не значит, что ты делаешь все правильно. Формат даты зависит от многих факторов, таких как локализация, региональные настройки и т.д.
Формат даты в MS SQL server может отличаться от пользовательских настроек. Это может вызвать у вас несколько проблем...

hareshdgr8

хорошо, сэр, не могли бы вы ответить на мой запрос в решении № 5

CHill60

Это действительно ужасно. Вам было бы лучше использовать решение 3. Если бы вы потрудились предоставить образцы данных, то любые проблемы могли бы быть устранены для вас.

hareshdgr8

решение 3 неверно, сэр, это было мое предыдущее решение, но оно не работает должным образом. записей, не совпадающих с этим .

CHill60

Как я уже сказал, Вы не предоставили нам никаких образцов данных для проверки каких-либо решений

hareshdgr8

Perf_Date
--------------------------------
2019-09-11 00:00:00.000
2019-09-12 00:00:00.000
2019-09-14 00:00:00.000
2019-09-15 00:00:00.000
2019-09-16 00:00:00.000
2019-09-17 00:00:00.000
2019-09-18 00:00:00.000
2019-09-19 00:00:00.000
2019-09-20 00:00:00.000
2019-09-21 00:00:00.000
2019-09-22 00:00:00.000
2019-09-23 00:00:00.000
2019-09-24 00:00:00.000
2019-09-25 00:00:00.000
2019-09-26 00:00:00.000
2019-09-27 00:00:00.000
2019-12-19 00:00:00.000
2019-12-20 00:00:00.000
2019-12-22 00:00:00.000
2019-12-23 00:00:00.000
2020-01-03 00:00:00.000
2020-01-04 00:00:00.000
2020-01-06 00:00:00.000
2020-01-07 00:00:00.000
2020-01-08 00:00:00.000
2020-01-09 00:00:00.000
2020-01-31 00:00:00.000
2020-02-01 00:00:00.000
2020-02-06 00:00:00.000
2020-02-07 00:00:00.000
2020-02-08 00:00:00.000
2020-02-17 00:00:00.000
2020-02-25 00:00:00.000
2020-03-01 00:00:00.000
2020-03-02 00:00:00.000

Это мои данные я хочу данные за январь месяц а также я хочу перед янв месяцем данные оба случая должны запустить один и тот же запрос что я могу сделать сэр
мой параметр-месяц/год, т. е. 01/2020, поэтому я хочу "=01/2020" или "<01/2020"

Maciej Los

Я создал скрипку для тебя: Скрипка SQL[^]. Проверьте это. Это работает!!!