我有一张表格,其中存储了有关汽车更改的详细信息(零件更改)。
例如,这里是CarChangeHistory表,对几辆车中的零件进行了少量更改(零件名称在另一个表中预定义,并且永远不会与该默认列表不同):
CarChangeHistory
CarGUID PartName PNPNNewValue TimeOfChange
X123 Windshield 344DFSS
X133 Lights BN23112
X899 Battery DNNN222
X433 Battery SM12345
汽车表看起来像这样:
CarTable
CarGUID Lights Windshield Battery Handle Door Mfg
X123 11111 344DFSS
CarChangeHistory表中还有许多其他类似的条目。
如果以下where子句为真,我想执行搜索并返回属于最近7天窗口内的所有项目:
(Lights LIKE %BN%) AND (Battery = 'DLK222' OR Windshield = true) AND (...) AND (...)
我可以将其转换为与我的表匹配到类似的东西(这是更合乎逻辑的伪代码。因为如果我将在SQL查询中单独使用它将不返回任何内容。因为上面的AND连接将尝试对每个原始进行AND,但我想在过去7天内每N次更改/原始数量执行此操作):
(PartName = 'Lights' AND PNNewValue LIKE '%BN%')
AND
((PartName = 'Battery' AND PNNewValue = 'DLK222') OR (PartName = 'Windshield'))
AND
(...)
AND
(...)
所以..如果我忽略空(...)
,使用上面的示例表,它会返回:
X123 Windshield 344DFSS
X133 Lights BN23112
如果我的示例没有与Lights
对齐,则不返回任何内容......
我猜最大的问题是AND连接,我如何在这样的查询中对待它?如何使用此where子句执行此类搜索?
我已经尝试了以下内容并且它有效,但我需要更改where子句(通过将(Lights LIKE %BN%) AND (Battery = 'DLK222' OR Windshield = true)
扩展为(Lights LIKE %BN% OR Windshield = true) OR (Lights LIKE %BN% OR Battery = 'DLK222')
)。我想如果我有更多的条件,它会变得相当复杂。
SELECT TimeOfChange, CarGUID
FROM CarChangeHistory
WHERE (
(((PartName = 'Lights' AND PNNewValue LIKE '%BN%') OR (PartName = 'Battery' AND PNNewValue = 'DLK222')))
OR
(((PartName = 'Lights' AND PNNewValue LIKE '%BN%') OR (PartName = 'Windshield')))
) AND TimeOfChange BETWEEN DATEADD(DAY,-7,GETDATE()) AND GETDATE()
GROUP BY TimeOfChange, CarGUID
HAVING COUNT(*) = 2
有谁知道这个问题的更好解决方案?转换我的逻辑where子句的最佳方法是什么,如果我运行的话,它只会返回任何内容,它可以在过去7天(或任何时间窗口)中实际过滤表中的数据。
答案 0 :(得分:1)
如果我理解正确,您希望在历史记录表中查找更改。此表没有名为Windshield,Lights等的列,而是包含PartName列。因此,对于一条记录,您有一个PartName。它不能同时是'挡风玻璃'和'灯'。这为您提供了两个选项:
1)使用EXISTS条款:
select carguid
from cars c
where exists
(
select *
from carchangehistory cch
where cch.carguid = c.carguid
and partname = 'Lights' and pnnewvalue like '%BN%'
and timeofchange between dateadd(day,-7,getdate()) and getdate()
)
and exists
(
select *
from carchangehistory cch
where cch.carguid = c.carguid
and ((partname = 'Battery' and pnnewvalue = 'DLK222') or (partname = 'Windshield'))
and timeofchange between dateadd(day,-7,getdate()) and getdate()
)
and exists
(
...
)
这将为您提供所有在过去7天内进行了所有查找更改的汽车。但是它一次又一次地查询同一个表。
2)使用带有条件HAVING子句的GROUP BY
select carguid
from carchangehistory
where timeofchange between dateadd(day,-7,getdate()) and getdate()
group by carguid
having count(case when partname = 'Lights' and pnnewvalue like '%BN%' then 1 end) > 0
and count(case when (partname = 'Battery' and pnnewvalue = 'DLK222') or partname = 'Windshield' then 1 end) > 0
and count(case when ... then 1 end) > 0
...;
这会给你相同的结果,但只扫描你的历史记录表一次。