【发布时间】:2017-01-05 17:43:56
【问题描述】:
我正在使用 C# Window 应用程序通过使用 SQL 查询从 Microsoft Access 中提取数据进行一些检查。
我有 2 个表要比较并选择数据。
- 表 1:USER_OF_RUN 由 StartDate 和 EndDate 组成
- 表 2:我需要加入表 1 并拉出的 USERINFO StartDate 和 EndDate 表的日期范围内的数据。
如果我的表 1 的 StartDate 和 EndDate 设置为 2016 年 1 月 1 日至 2017 年 12 月 31 日,则所有数据都是正确的。但是,当范围设置为例如 22/12/2016 到 31/12/2017 时,我想要提取的数据来自日期 3/1/2017,该日期介于日期范围之间,但不知何故数据是空的。
我很好奇我的查询是错误的还是我遗漏了一些语法。
这是我的 SQL 查询:
SELECT
FORMAT(A.CHECKTIME,'dd/mm/yyyy') AS CHECKTIME,
A.USERID AS USERID,
B.NAME AS NAME,
B.BADGENUMBER AS BADGENUMBER,
C.NUM_OF_RUN_ID,
D.NAME AS DEPT,
DEFAULTDEPTID
FROM ((((CHECKINOUT A )
LEFT JOIN USERINFO B
ON A.USERID = B.USERID )
LEFT JOIN USER_OF_RUN C
ON A.USERID = C.USERID )
LEFT JOIN NUM_RUN D
ON C.NUM_OF_RUN_ID = D.NUM_RUNID )
WHERE
Format(A.CHECKTIME, 'dd/mm/yyyy') IN (Format('03/01/2017', 'dd/mm/yyyy'), Format(DateAdd('d', 1, Format('03/01/2017', 'dd/mm/yyyy')), 'dd/mm/yyyy'))
AND Format('03/01/2017', 'dd/mm/yyyy') BETWEEN Format(C.STARTDATE, 'dd/mm/yyyy') AND Format(C.ENDDATE, 'dd/mm/yyyy')
AND DEFAULTDEPTID = 4
AND BADGENUMBER = '7092'
ORDER BY A.USERID DESC, CHECKTIME asc
UNION ALL
SELECT
distinct '',
USERID,
NAME,
BADGENUMBER,
'',
'',
''
FROM USERINFO
WHERE userid NOT IN
(SELECT DISTINCT A.USERID AS USERID
FROM ((((CHECKINOUT A)
LEFT JOIN USERINFO B
ON A.USERID = B.USERID )
LEFT JOIN USER_OF_RUN C
ON A.USERID = C.USERID )
LEFT JOIN NUM_RUN D
ON C.NUM_OF_RUN_ID = D.NUM_RUNID )
WHERE Format (A.CHECKTIME, 'dd/mm/yyyy') = Format('03/01/2017', 'dd/mm/yyyy')
AND Format('03/01/2017', 'dd/mm/yyyy') BETWEEN Format(C.STARTDATE, 'dd/mm/yy') AND Format(C.ENDDATE, 'dd/mm/yyyy'))
AND DEFAULTDEPTID = 4
AND BADGENUMBER = '7092'
【问题讨论】:
-
您的查询在这样的单行上是不可读的——即使不是这样,它也比它需要的复杂得多。请将其减少为 minimal 查询。 (您是否尝试过不使用连接进行查询?)
-
我的印象是您将日期存储为字符串。我说的对吗?
-
正如史蒂夫暗示的那样,将日期存储为字符串是一个非常非常糟糕的主意 - 特别是考虑到您没有以可排序的顺序存储它们! (在词汇上,字符串“01/01/2020”出现在“10/01/2016”之前——但你不希望这样......)
-
补充@JonSkeet 所说的,如果您将日期存储为字符串,那么您应该在比较它们之前将它们转换为日期
-
@MarcusZac:嗯,就是这样——就像字符串“abc”出现在“bcd”之前一样。当您比较字符串 时,您基本上首先查看第一个字符...并且“0”在“1”之前。 (比这复杂一点,但从根本上说明了问题。)