Использование DATETIME в предложении WHERE в SQL Server - PullRequest
0 голосов
/ 07 мая 2018

У меня есть этот запрос

SELECT  
    [MsgNumber], [StateAfter],
    DATETIMEFROMPARTS (SUBSTRING([TimeString], 7, 4), 
                       SUBSTRING([TimeString], 4, 2), 
                       SUBSTRING([TimeString], 1, 2),
                       SUBSTRING([TimeString], 12, 2), 
                       SUBSTRING([TimeString], 15, 2), 
                       SUBSTRING([TimeString], 18, 2), 0) AS dt
FROM 
    TABLE
WHERE 
    [MsgNumber] IN (5, 9, 13, 17)
ORDER BY 
    dt ASC, StateAfter ASC

ВЫХОД (ок):

+-----------+-----------+-------------------------+
| MsgNumber | tateAfter |           dt            |
+-----------+-----------+-------------------------+
|         9 |         1 | 2018-03-09 17:22:00.000 |
|         9 |         0 | 2018-03-09 17:23:37.000 |
|        17 |         1 | 2018-03-09 17:23:37.000 |
|        17 |         1 | 2018-03-09 17:29:43.000 |
|        17 |         1 | 2018-03-09 17:36:21.000 |
+-----------+-----------+-------------------------+

Я хочу добавить условие на дату; чтобы избежать ошибок во внутреннем кодировании даты и времени, я использую функцию DATETIMEFROMPARTS, например:

SELECT [MsgNumber],[StateAfter]
,DATETIMEFROMPARTS ( SUBSTRING ( [TimeString] ,7 , 4 ), SUBSTRING ( [TimeString] ,4 , 2 ), SUBSTRING ( [TimeString] ,1 , 2 ),
                    SUBSTRING ( [TimeString] ,12 , 2 ), SUBSTRING ( [TimeString] ,15 , 2 ), SUBSTRING ( [TimeString] ,18 , 2 ) , 0) as dt
FROM TABLE
WHERE [MsgNumber] IN (5,9,13,17) AND (dt > DATETIMEFROMPARTS(2018,4,9,0,0,0,0) and dt <  DATETIMEFROMPARTS(2018,5,9,0,0,0,0))
ORDER BY dt ASC,StateAfter ASC

ОШИБКА: -

Messaggio 207, livello 16, stato 1, riga 5
Неверное имя столбца 'dt'.
Messaggio 207, livello 16, stato 1, riga 5
Неверное имя столбца 'dt'.

Может ли кто-нибудь помочь мне понять, почему это не работает? Я попробовал также предложение BETWEEN; Спасибо

Ответы [ 4 ]

0 голосов
/ 07 мая 2018

Эта ошибка устранена, поскольку dt не является физическим столбцом.

Вы можете достичь как ниже запрос:

    SELECT tbl.* FROM ( SELECT  
        [MsgNumber], [StateAfter],
        DATETIMEFROMPARTS (SUBSTRING([TimeString], 7, 4), 
                           SUBSTRING([TimeString], 4, 2), 
                           SUBSTRING([TimeString], 1, 2),
                           SUBSTRING([TimeString], 12, 2), 
                           SUBSTRING([TimeString], 15, 2), 
                           SUBSTRING([TimeString], 18, 2), 0) AS dt
    FROM 
        TABLE ) tbl
    WHERE tbl.[MsgNumber] IN (5,9,13,17) 
AND (tbl.dt > DATETIMEFROMPARTS(2018,4,9,0,0,0,0) AND tbl.dt <  DATETIMEFROMPARTS(2018,5,9,0,0,0,0)) 
    ORDER BY 
        tbl.dt ASC, tbl.StateAfter ASC
0 голосов
/ 07 мая 2018

Псевдоним dt нельзя использовать внутри предложения WHERE. Используйте подзапрос, например:

 SELECT t.[MsgNumber]
    ,t.[StateAfter]
    ,t.dt
FROM (
    SELECT [MsgNumber]
        ,[StateAfter]
        ,DATETIMEFROMPARTS(SUBSTRING([TimeString], 7, 4), SUBSTRING([TimeString], 4, 2), SUBSTRING([TimeString], 1, 2), SUBSTRING([TimeString], 12, 2), SUBSTRING([TimeString], 15, 2), SUBSTRING([TimeString], 18, 2), 0) AS dt
    FROM TABLE
    ) t
WHERE [MsgNumber] IN (
        5
        ,9
        ,13
        ,17
        )
    AND (
        dt > DATETIMEFROMPARTS(2018, 4, 9, 0, 0, 0, 0)
        AND dt < DATETIMEFROMPARTS(2018, 5, 9, 0, 0, 0, 0)
        )
ORDER BY dt ASC
    ,StateAfter ASC
0 голосов
/ 07 мая 2018

Вы получаете эту ошибку, потому что в вашей таблице нет такого столбца dt. Это просто Псевдоним, который вы дали в списке выбора, поэтому он не является Столбцом. Таким образом, Вы можете использовать любой из следующих методов:

Использование CTE или SubQuery (рекомендуется)

; with CTE
AS
(
    SELECT [MsgNumber],[StateAfter]
    ,DATETIMEFROMPARTS ( SUBSTRING ( [TimeString] ,7 , 4 ), SUBSTRING ( [TimeString] ,4 , 2 ), SUBSTRING ( [TimeString] ,1 , 2 ),

SUBSTRING ( [TimeString] ,12 , 2 ), 
SUBSTRING ( [TimeString] ,15 , 2 ), SUBSTRING ( [TimeString] ,18 , 2 ) , 0) as dt
        FROM TABLE
)
SELECT
    *
    FROM CTE
WHERE [MsgNumber] IN (5,9,13,17) 
    AND 
(
dt > DATETIMEFROMPARTS(2018,4,9,0,0,0,0) and dt <  DATETIMEFROMPARTS(2018,5,9,0,0,0,0))
    ORDER BY dt ASC,StateAfter ASC

Формула, в которой условие (не рекомендуется)

SELECT [MsgNumber],[StateAfter]
,DATETIMEFROMPARTS ( SUBSTRING ( [TimeString] ,7 , 4 ), SUBSTRING ( [TimeString] ,4 , 2 ), SUBSTRING ( [TimeString] ,1 , 2 ),
                    SUBSTRING ( [TimeString] ,12 , 2 ), SUBSTRING ( [TimeString] ,15 , 2 ), SUBSTRING ( [TimeString] ,18 , 2 ) , 0) as dt
FROM [TABLE]
WHERE [MsgNumber] IN (5,9,13,17) AND 
(
    DATETIMEFROMPARTS ( SUBSTRING ( [TimeString] ,7 , 4 ), SUBSTRING ( [TimeString] ,4 , 2 ), SUBSTRING ( [TimeString] ,1 , 2 ),
                    SUBSTRING ( [TimeString] ,12 , 2 ), SUBSTRING ( [TimeString] ,15 , 2 ), SUBSTRING ( [TimeString] ,18 , 2 ) , 0)
                > DATETIMEFROMPARTS(2018,4,9,0,0,0,0) 
    and 
    DATETIMEFROMPARTS ( SUBSTRING ( [TimeString] ,7 , 4 ), SUBSTRING ( [TimeString] ,4 , 2 ), SUBSTRING ( [TimeString] ,1 , 2 ),
                    SUBSTRING ( [TimeString] ,12 , 2 ), SUBSTRING ( [TimeString] ,15 , 2 ), SUBSTRING ( [TimeString] ,18 , 2 ) , 0)
                <  DATETIMEFROMPARTS(2018,5,9,0,0,0,0))
ORDER BY dt ASC,StateAfter ASC
0 голосов
/ 07 мая 2018

Нельзя ссылаться на псевдоним столбца в предложении where. Типичные решения - использовать подзапросы или CTE. Но у SQL Server есть другой метод, который мне нравится, apply:

SELECT [MsgNumber], [StateAfter], v.dt
FROM TABLE t CROSS APPLY
     (VALUES (DATETIMEFROMPARTS(SUBSTRING ([TimeString], 7, 4), SUBSTRING([TimeString], 4, 2), SUBSTRING([TimeString], 1, 2),
                    SUBSTRING([TimeString], 12, 2), SUBSTRING( [TimeString], 15, 2), SUBSTRING([TimeString], 18, 2), 0)
             )
     ) V(dt)
WHERE [MsgNumber] IN (5, 9, 13, 17) AND
      v.dt > DATETIMEFROMPARTS(2018, 4, 9, 0, 0, 0, 0) AND
      v.dt <  DATETIMEFROMPARTS(2018, 5, 9, 0, 0, 0, 0))
ORDER BY dt ASC,StateAfter ASC;

Мне любопытно, что вы не используете более простое:

WHERE [MsgNumber] IN (5, 9, 13, 17) AND
      v.dt > '20180409'  AND
      v.dt < '20180509'

(Я не использовал дефисы, потому что этот формат всегда будет интерпретироваться как ГГГГММДД независимо от настроек интернационализации.)

...