选择SQL中不存在的所有值

时间:2018-06-26 14:04:29

标签: sql

当前,我的查询选择了我的WHERE子句中指定的所有位置,并返回了所有包含提供邮政编码的位置的邮政编码。 我的目标是返回所有带有未提供送货地区的邮政编码的位置。数据库中有成千上万个邮政编码,所以不是NOT的选择,因为我需要将结果限制在这些邮政编码中。我觉得这很容易实现,但是解决方案使我逃脱了。

SELECT ORS.PostDate
,ORS.Name
,ORS.Address
,ORS.City
,ORS.State
,ORS.Zip
,ORS.DriverID
,W.FirstName
,W.LastName
,ORS.RouteID


FROM tblOrderRouteStops ORS WITH (NOLOCK)
INNER JOIN tblWorker W WITH (NOLOCK) ON W.WorkerID = ORS.DriverID

--Select all distinct zips from tblOrderRouteStops, then use where clause to filter them to specified locations.
FULL OUTER JOIN 
(SELECT DISTINCT ORSS.Zip FROM
tblOrderRouteStops ORSS WITH (NOLOCK)) as B
ON B.Zip = ORS.Zip

WHERE ORS.PostDate >= dateadd(day,datediff(day,1,GETDATE()),0)
AND ORS.PostDate < dateadd(day,datediff(day,0,GETDATE()),0)
AND ORS.CustID = 104105
AND ORS.StopType = 1
AND (ORS.Zip = 16635
OR ORS.Zip = 25504
OR ORS.Zip = 28401
OR ORS.Zip = 28803
OR ORS.Zip = 30901
OR ORS.Zip = 31904
OR ORS.Zip = 35801
OR ORS.Zip = 37921
OR ORS.Zip = 38801
OR ORS.Zip = 39232
OR ORS.Zip = 46825
OR ORS.Zip = 49428
OR ORS.Zip = 50265
OR ORS.Zip = 54915
OR ORS.Zip = 67214
OR ORS.Zip = 72205
OR ORS.Zip = 72764
OR ORS.Zip = 72916
OR ORS.Zip = 79605)

2 个答案:

答案 0 :(得分:1)

使用NOT IN运算符,如

AND ORS.Zip NOT IN (16635,25504,....)

答案 1 :(得分:0)

这是一个快速的过程。我接受了原始查询并对其进行了修改,并使用“ before and after”变体,该变体基于最后使用AND子句的情况。

首先,设置一个包含“目标”邮政编码的临时表。使用起来会更容易,SQL会产生更好的执行计划。

DECLARE @TargetZips table
    (
    Zip  char(5)  not null  --  Replace with the datatype you are using
    )

INSERT @TargetZips values
    (16635)
    ,(25504)
    ,(28401)
    ,(28803)
    ,(30901)
    ,(31904)
    ,(35801)
    ,(37921)
    ,(38801)
    ,(39232)
    ,(46825)
    ,(49428)
    ,(50265)
    ,(54915)
    ,(67214)
    ,(72205)
    ,(72764)
    ,(72916)
    ,(79605)

然后查询:

SELECT
 ORS.PostDate
,ORS.Name
,ORS.Address
,ORS.City
,ORS.State
,ORS.Zip
,ORS.DriverID
,W.FirstName
,W.LastName
,ORS.RouteID


FROM tblOrderRouteStops ORS
 INNER JOIN tblWorker W
  ON W.WorkerID = ORS.DriverID

--Select all distinct zips from tblOrderRouteStops, then use where clause to filter them to specified locations.
 FULL OUTER JOIN (--  Restrict this to the set of zip codes you are intersted in
                  SELECT DISTINCT ORSS.Zip
                   FROM tblOrderRouteStops ORSS
                    INNER JOIN @TargetZips tz
                     on tz.Zip = ORSS.zip
                 ) as B
  ON B.Zip = ORS.Zip

WHERE ORS.PostDate >= dateadd(day,datediff(day,1,GETDATE()),0)
AND ORS.PostDate < dateadd(day,datediff(day,0,GETDATE()),0)
AND ORS.CustID = 104105
AND ORS.StopType = 1

将其包含在原始查询中

AND B.Zip is not null

在修改后的查询中添加

AND B.Zip is null

理想情况下,您有两个单独的查询。这样,您就可以避免使用FULL OUTER JOIN了-我建议这样做,它们总是会让我感到紧张。

-编辑------------------------

以下内容,恕我直言,虽然很笨拙,但可以避免使用INSERT:

WITH cteTargetZip 
 as (--  Build a table set based entirely on a values clause
     select Zip
      from (values  (16635)
                   ,(25504)
                   ,(28401)
                   ,(28803)
                   ,(30901)
                   ,(31904)
                   ,(35801)
                   ,(37921)
                   ,(38801)
                   ,(39232)
                   ,(46825)
                   ,(49428)
                   ,(50265)
                   ,(54915)
                   ,(67214)
                   ,(72205)
                   ,(72764)
                   ,(72916)
                   ,(79605)
          ) as TargetZips (Zip)
    )
SELECT...

,然后在主查询中将@TargetZips替换为cteTargetZips

-第二次编辑-----------------------------------------

好吧,这有望完成必要的工作...

--  Query will return all zip codes in the CTE expression that are not found
--  in your selected delivery locations.  On large tables it will perform
--  poorly, unless there is an index on tblOrderRouteStops.Zip
WITH cteTargetZip 
    as (--  Build a table set based entirely on a values clause
        select Zip
        from (values  (16635)
                    ,(25504)
                    ,(28401)
                    ,(28803)
                    ,(30901)
                    ,(31904)
                    ,(35801)
                    ,(37921)
                    ,(38801)
                    ,(39232)
                    ,(46825)
                    ,(49428)
                    ,(50265)
                    ,(54915)
                    ,(67214)
                    ,(72205)
                    ,(72764)
                    ,(72916)
                    ,(79605)
            ) as TargetZips (Zip)
    )
SELECT cte.Zip
FROM cteTargetZip cte
WHERE not exists (--  The set of delivered-to locations you are interested in
                  --  If every tblOrderRouteStops always has at least one tblWorker,
                  --   you can drop the join.
                    SELECT 1
                    FROM tblOrderRouteStops ORS
                        INNER JOIN tblWorker W
                        ON W.WorkerID = ORS.DriverID
                    WHERE ORS.PostDate >= dateadd(day,datediff(day,1,GETDATE()),0)
                    AND ORS.PostDate < dateadd(day,datediff(day,0,GETDATE()),0)
                    AND ORS.CustID = 104105
                    AND ORS.StopType = 1
                    AND ORS.Zip = cte.Zip  --  Technically, this line makes it a correlated subquery
                    )