SQL查询 - 如果未满足要求,则需要排除,如果满足要求,则排除

时间:2012-02-12 07:10:45

标签: sql-server sql-server-2008 tsql

我有一种感觉,一旦我看到解决方案,我会打我的额头,但现在我没有看到它。

我有一个查找表,比如TableB,看起来像这样。除了最后两个是BOOL之外,所有字段都是INT

ID, TableA_ID, Value, Required, Disqualifies

我有一个TableA_Id值列表(1, 2, 3 )

对于此表中的每条记录,要么必须为真,要么取消资格可以为真 - 它们不能同时为真。它们既可以是假的也可以是空的。可能存在TableA_Id的重复值,但绝不应重复TableA_IdValue

如果对于任何这些TableA_ID值都是必需的,并且这些值都不在我的列表中,则不返回任何记录。如果没有任何值被标记为必需(required = 0 or null),则返回记录 UNLESS 任何值都被标记为取消资格并且在列表中,在这种情况下我想不返回任何记录。< / p>

所以 - 如果一个字段是必需的,我没有它,不要返回任何记录。如果某个字段被标记为取消资格且我拥有该字段,请不要返回任何记录。如果我有一个必需的值或者没有取消资格或者没有必要的值,则只返回记录。

我希望我能清楚地解释自己。

提前感谢我指出了正确的方向。

作为我的记录可能的样子的一个例子:

ID  TableA_ID  Value  Required  Disqualifies
--  ---------  -----  --------  ------------
1   123        1      True      False
2   123        2      True      False
3   123        3      False     False
4   123        4      False     True
5   456        1      False     True
6   456        2      False     False

鉴于这组样本数据,如果我们使用TableA_Id 123并且我的值列表是1和3,我会得到数据,因为我有一个必需的值而且没有任何取消资格值。如果我的值列表只有3,那么我没有记录,因为我缺少必需的值。如果我的值列表是1和4,我将没有记录,因为4被标记为取消资格。

现在,如果我们使用TableA_Id 456,那么唯一可以返回任何记录的值列表是2.

也许我应该发布整个SQL查询 - 我试图保持这个简短,以便让每个人都更容易,但看起来可能不是那么好。

这是完整动态生成的查询。我现在正在处理的是从底部开始的第二行。要将此等同于我的示例,t.id将为TableA_IDValue将为PDT_ID

SELECT DISTINCT t.ID, t.BriefTitle, stat.Status, lstat.Status AS LocationStatus, st.SType, t.LAgency, l.City, state.StateCode
,( SELECT TOP 1 UserID  
FROM TRecruiter 
WHERE TrialID = t.ID AND Lead = 1 ), l.ID as LocationID
, l.WebBased 
FROM Trial t 
INNER JOIN Location l ON t.ID = l.TrialID       
FULL JOIN pdt on t.ID = pdt.trialid       
FULL JOIN pdm on t.ID = pdm.TrialID       
FULL JOIN s on t.ID = s.TrialID       
FULL JOIN hy on t.ID = hy.TrialID       
FULL JOIN ta on t.ID = ta.TrialID       
FULL JOIN stt on t.ID = stt.TrialID       
FULL JOIN [Status] stat ON t.StatusID = stat.ID       
FULL JOIN st ON t.StudyTypeID = st.ID       
FULL JOIN State state ON l.StateID = state.ID       
FULL JOIN [Status] lstat ON l.StatusID = lstat.ID       
FULL JOIN ts ON t.ID = ts.TrialID       
FULL JOIN tpdm ON t.ID = tpdm.TrialID      
WHERE ((t.ID IS NOT NULL) 
AND (EligibleHealthyVolunteers IS NULL OR EligibleHealthyVolunteers = 1 OR (0 = 0 AND EligibleHealthyVolunteers = 0)) 
AND (eligiblegenderid is null OR eligiblegenderid = 1 OR eligiblegenderid = 3) 
AND ((EligibleMinAge <= 28 AND EligibleMaxAge >= 28) OR (EligibleMinAge <= 28 AND EligibleMaxAge is null) OR (EligibleMinAge IS NULL AND EligibleMaxAge >= 28)) 
AND (HYID = 6 AND (hy.Disqualify = 0 OR hy.Disqualify IS NULL AND NOT EXISTS (SELECT * FROM hy WHERE t.id = hy.TrialID AND hy.Req =1)) OR HYID = 6 AND hy.req = 1)
AND (PDT_ID IN (1) AND ( pdt.Disqualify = 0 OR pdt.Disqualify IS NULL AND NOT EXISTS (select * from pdt where t.id = pdt.TrialID AND pdt.Req = 1)) OR PDT_ID IN (1) AND (pdt.Req = 1 AND (pdt.Disqualify = 0 or pdt.Disqualify is null )))      
) AND ((3959 * acos(cos(radians(34.18)) * cos(radians(l.Latitude)) * cos(radians(l.Longitude) - radians(-118.46)) + sin(radians(34.18)) * sin(radians(l.Latitude)))) <= 300 OR l.Latitude IS NULL) AND t.IsPublished = 1 AND (t.StatusID = 1 OR t.StatusID = 2) 

我出于安全/隐私原因更改/缩短了一些表名。

修改 我认为我已接近完成这项工作,但我再次绊倒了逻辑。

我有以下一点sql:

AND ( exists (SELECT * FROM  pdt WHERE Req = 1 AND trialid = t.id AND pdT_ID IN (2) )  AND EXISTS (SELECT * FROM  pdt WHERE Req = 1 AND trialid = t.id    )     )

我不确定如何构建它。这两个存在的语句应该在以下组合中使整个事情成为现实: 真实&amp;假 真实&amp;真正 虚假&amp;假

如果它是假的&amp;没错,那么整件事都是假的。换句话说,如果Req = 1并且标记为Req = 1的PDT_ID不在我们的列表中(在上面的示例中,列表只包含'2')则返回false。

修改 我想我终于明白了。

AND NOT EXISTS (SELECT * FROM  pdt WHERE Disqualify = 1 AND trialid = t.id AND  PDT_ID IN (2)  )
AND NOT ( NOT exists (SELECT * FROM  pdt WHERE Req = 1 AND trialid = t.id AND PDT_ID IN (2) )  AND EXISTS (SELECT * FROM  pdt WHERE Req = 1 AND trialid = t.id    )  )

到目前为止,这似乎在测试中起作用。虽然我只使用两个PDT_ID值。如果这确实解决了我的问题,我会回来给别人一个帮助我的功劳。

3 个答案:

答案 0 :(得分:0)

更新 - 在编辑和OP解释之后:

更改行

FULL JOIN pdt on t.ID = pdt.trialid

FULL JOIN (SELECT * FROM pdt BB WHERE
BB.TrialID IN (SELECT AA.ID FROM Trial AA WHERE AA.ID = BB.TrialID) AND
1 > (SELECT COUNT(*) FROM Trial A
LEFT OUTER JOIN pdt B ON B.Req != 1 AND B.Disqualify != 1 AND B.TrialID = A.ID
WHERE B.TrialID IS NULL)) pdt ON t.ID = pdt.TiralID

开始更改前一行
AND (PDT_ID IN (1) AND ( pdt.Disqualify = 0 OR pdt.Disqualify IS NULL AND NOT EXISTS (select * from pdt where t.id = pdt.TrialID AND pdt.Req = 1)) OR PDT_ID IN (1) AND (pdt.Req = 1 AND (pdt.Disqualify = 0 or pdt.Disqualify is null ))) 

AND PDT_ID IN (1)

答案 1 :(得分:0)

SELECT * 
FROM TABLEB B
WHERE 
(
   B.REQUIRED = 1 
   AND EXISTS
   (
     SELECT 1
     FROM TABLEA A
     WHERE A.ID =B.TABLEA_ID
   )
)
OR
(
  B.REQUIRED != 1
  AND B.DISQUALIFIES <> 1

)
OR
(
    B.REQUIRED != 1
    AND B.DISQUALIFIES = 1
    AND EXISTS
    (
     SELECT 1
     FROM TABLEA A
     WHERE A.ID =B.TABLEA_ID
    ) 

)

答案 2 :(得分:0)

(您似乎找到了解决方案,但我决定分享我对此问题的看法。)

鉴于您有一组TableA个ID,每个ID都附带一组值,并且您希望使用规则测试针对此TableB事物的整个行集你提出了,我认为整个检查过程可能如下:

  1. 将每对TableA.IDValueTableB匹配,并为每Required获得DisqualifiesTableA.ID的汇总最大值一路走来。

  2. TableA_ID派生一个单独的Required值列表及其对应的最大值TableB。这将是我们知道特定的TableA_ID 是否必须具有所需的值。

  3. 将第1阶段获得的行集与派生表(第2阶段)匹配,并检查汇总值:

    1)如果Disqualifies的实际汇总TableA_ID1,则弃置此TableA_ID集;

    2)如果TableA_ID在第2阶段派生表中匹配,并且我们在第1阶段获得的最大Required的最大值与最大Required匹配派生表,也丢弃该集。

  4. 有些东西告诉我,在这一点上更好地继续进行某种说明。这是一个示例脚本,其中的注释解释了脚本的哪一部分实现了上述描述的哪一部分:

    ;
    WITH
    
    /* this is the row set to be tested and which
       is supposed to contain TableA.IDs and Values */
    testedRowSet AS (
      SELECT
        TableA.ID AS TableA_ID,
        SomethingElse.TestedValue AS Value,
        ...
      FROM TableA
        JOIN SomethingElse ON some_condition
        ...
    ),
    
    /* at this point, we are getting the aggregate maximums
       of TableB.Required and TableB.Disqualifies for every
       TableA_ID in testedRowSet */
    aggregated AS (
      SELECT
        testedRowSet.TableA_ID,
        testedRowSet.Value,
        ...
        DoesHaveRequiredValues = MAX(CASE TableB.Required     WHEN 1 THEN 1 ELSE 0 END) OVER (PARTITION BY testedRowSet.TableA_ID),
        HasDisqualifyingValues = MAX(CASE TableB.Disqualifies WHEN 1 THEN 1 ELSE 0 END) OVER (PARTITION BY testedRowSet.TableA_ID)
      FROM testedRowSet
        LEFT JOIN TableB ON testedRowSet.TableA_ID = TableB.TableA_ID
                        AND testedRowSet.Value     = TableB.Value
    ),
    
    /* this row set will let us see whether a particular
       TableA_ID must have a required value */
    properties AS (
      SELECT
        TableA_ID,
        MustHaveRequiredValues = MAX(CASE Required WHEN 1 THEN 1 ELSE 0 END)
      FROM TableB
      GROUP BY TableA_ID
    ),
    
    /* this is where we are actually checking the previously
       obtained aggregate values of Required and Disqualifies */
    tested AS (
      SELECT
        aggregated.TableA_ID,
        aggregated.Value,
        ...
      FROM aggregated
        LEFT JOIN properties ON aggregated.TableA_ID = properties.TableA_ID
      WHERE aggregated.HasDisqualifyingValues = 0
        AND (properties.TableA_ID IS NULL
          OR properties.MustHaveRequiredValues = aggregated.DoesHaveRequiredValues)
    )
    
    SELECT * FROM tested