根据条件在SQL表中查找缺失的条目

时间:2018-10-17 07:21:20

标签: sql sql-server outer-join sql-except

我有一定程度的简单SQL经验(在此处使用MS SQL Server 2012),但这使我回避了。我希望从一个表(以前是通过联接成功创建)中输出不同的名称,该表缺少一些必需的条目,但要以存在另一个相似的条目为条件。对于位置为90的人,我想检查一下它们是否也具有位置10和20 ...

例如,考虑此表:

Name    |Number |Location
--------|-------|--------
Alice   |136218 |90
Alice   |136218 |10
Alice   |136218 |20
Alice   |136218 |40
Bob     |121478 |10
Bob     |121478 |90
Chris   |147835 |20
Chris   |147835 |90
Don     |138396 |20
Don     |138396 |10
Emma    |136412 |10
Emma    |136412 |20
Emma    |136412 |90
Fred    |158647 |90
Gay     |154221 |90
Gay     |154221 |10
Gay     |154221 |30

因此,我想正式获得表中那些条目的名称(和编号):

  1. 在位置90处有一个条目
  2. 并且没有所有其他必需的位置条目-在这种情况下也为10和20。

所以在上面的示例中

  • 此查询未输出Alice和Emma,它们具有90、10和20的条目(全部存在且正确,我们忽略了位置40的条目)。
  • 此查询未输出Don,他没有位置90的条目。
  • 此查询输出的是鲍勃和盖伊,他们都缺少位置20(我们忽略了盖伊的位置30条目)。
  • 此查询输出的是克里斯,他缺少位置10。
  • 此查询输出的是弗雷德,他缺少位置10和20。

因此,所需的查询输出类似于:

Name    |Number |Location
--------|-------|--------
Bob     |121478 |20
Chris   |147835 |10
Fred    |158647 |10
Fred    |158647 |20
Gay     |154221 |20

我已经尝试了一些使用左/右联接的方法,其中B.Key为null,然后从...中进行选择,但到目前为止,我还不能完全理解逻辑方法。在原始表中,有成千上万的条目,只有几十个有效的缺失匹配项。不幸的是,由于查询必须特定于位置,并且在所需位置之外的其他位置还有其他有效的表条目,因此我无法使用任何可以计数条目的东西。

我认为执行此操作的正确方法类似于左外部联接,但是由于起始表是另一个联接的输出,这是否需要声明一个中间表,然后使用其自身对外部表进行外部联接?请注意,不需要填写任何空白或在表格中输入项目。

任何建议将不胜感激。

===已粘贴的已使用和已使用的代码===

    --STEP 0: Create a CTE of all valid actual data in the ranges that we want
WITH ValidSplits AS
(
    SELECT DISTINCT C.StartNo, S.ChipNo, S.TimingPointId
    FROM Splits AS S INNER JOIN Competitors AS C                    
        ON  S.ChipNo = C.ChipNo                     
            AND (                               
                S.TimingPointId IN (SELECT TimingPointId FROM @TimingPointCheck)
                OR
                S.TimingPointId = @TimingPointMasterCheck
            )
),

--STEP 1: Create a CTE of the actual data that is specific to the precondition of passing @TimingPointMasterCheck
MasterSplits AS
(
    SELECT DISTINCT StartNo, ChipNo, TimingPointId 
    FROM ValidSplits
        WHERE TimingPointId = @TimingPointMasterCheck           
)

--STEP 2: Create table of the other data we wish to see, i.e. a representation of the StartNo, ChipNo and TimingPointId of the finishers at the locations in @TimingPointCheck
--The key part here is the CROSS JOIN which makes a copy of every Start/ChipNo for every TimingPointId
SELECT StartNo, ChipNo, Missing.TimingPointId
FROM MasterSplits
    CROSS JOIN (SELECT * FROM @TimingPointCheck) AS Missing(TimingPointId)
EXCEPT
    SELECT StartNo, ChipNo, TimingPointId FROM ValidSplits
ORDER BY StartNo

2 个答案:

答案 0 :(得分:1)

欢迎使用堆栈溢出。

您需要的挑战性很大,因为您想查看不存在的数据。 因此,我们首先必须创建所有可能的行,然后减去存在的行

    select ppl_with_90.Name,ppl_with_90.Number,search_if_miss.Location 
    from
    (
        select distinct Name,Number
        from yourtable t
        where Location=90
    )ppl_with_90 -- All Name/Numbers that have the 90
    cross join (values (10),(20)) as search_if_miss(Location) -- For all the previous, combine them with both 10 and 20
except -- remove the lines already existing
    select * 
    from yourtable 
    where Location in (10,20)

答案 1 :(得分:1)

对于位置= 90的所有行,您需要生成name, number, 10_and_20组成的集合。然后,您可以使用自己喜欢的方法(左联接+ null,不存在,不在)过滤不存在​​的行:

WITH name_number_location AS (
    SELECT t.Name, t.Number, v.Location
    FROM @yourdata AS t
    CROSS JOIN (VALUES (10), (20)) AS v(Location)
    WHERE t.Location = 90
)
SELECT *
FROM name_number_location AS r
WHERE NOT EXISTS (
    SELECT *
    FROM @yourdata AS t
    WHERE r.Name = t.Name AND r.Location = t.Location
)