【问题标题】:Filter records with multiple columns过滤具有多列的记录
【发布时间】:2020-12-11 07:42:51
【问题描述】:

一个表中有 4 个属性。一次只能将一个属性设置为 Y。是否有一个 SQL Server 函数可以找到这个。

【问题讨论】:

  • 您要识别多于 1 组的记录吗?还是只想输出只有 1 组的有效记录?
  • 查看stackoverflow.com/questions/28717868/…。对于类似的问题,有几种解决方案。
  • 我想获取多个属性设置为 Y 的记录列表。

标签: sql sql-server tsql


【解决方案1】:

您可以使用以下布尔表达式来限制属性中最多一个“Y”值:

IIF(Attribute1 = 'Y', 1, 0) +
IIF(Attribute2 = 'Y', 1, 0) +
IIF(Attribute3 = 'Y', 1, 0) +
IIF(Attribute4 = 'Y', 1, 0) <= 1

【讨论】:

  • @sivabalanarayanan。 . . &lt;= 1 不符合您的问题要求。令人惊讶的是你接受了这个。
  • 令人惊讶的是,我们俩碰巧同时在看这个几个小时前的问题。
  • @GordonLinoff 当我将条件更改为它时它可以工作> 1.人们可能会忽略它。我在考虑 CASE 语句时接受了,IFF 是 CASE 的简写方式。
【解决方案2】:

你可以在这里使用连接技巧:

SELECT *
FROM yourTable
WHERE Attribute1 + Attribute2 + Attribute3 + Attribute4
      NOT LIKE '%Y%Y%';

但这也将匹配具有所有 4 个属性的 N 的记录。如果你也想坚持一个Y,但不超过一个Y,那就用这个版本:

SELECT *
FROM yourTable
WHERE
    Attribute1 + Attribute2 + Attribute3 + Attribute4 LIKE '%Y%' AND
    Attribute1 + Attribute2 + Attribute3 + Attribute4
      NOT LIKE '%Y%Y%';

【讨论】:

    【解决方案3】:

    如果您只想将记录标识为“有效”或“无效”,则可以执行以下操作:

    IF OBJECT_ID('tempdb..#Sample','U') IS NOT NULL DROP TABLE #Sample; --SELECT * FROM #Sample
    CREATE TABLE #Sample (
        Attribute1 char(1) NOT NULL,
        Attribute2 char(1) NOT NULL,
        Attribute3 char(1) NOT NULL,
        Attribute4 char(1) NOT NULL
    )
    
    INSERT INTO #Sample (Attribute1, Attribute2, Attribute3, Attribute4)
    VALUES ('Y','N','N','N')
        ,  ('N','Y','N','N')
        ,  ('N','N','Y','N')
        ,  ('N','N','N','Y')
        ,  ('N','N','Y','Y')
    
    SELECT *
        , IsValid = IIF(LEN(REPLACE(CONCAT(s.Attribute1, s.Attribute2, s.Attribute3, s.Attribute4),'Y','')) >= 3, 'Valid', 'Invalid')
    FROM #Sample s
    

    返回:

    | Attribute1 | Attribute2 | Attribute3 | Attribute4 | IsValid | 
    |------------|------------|------------|------------|---------| 
    | Y          | N          | N          | N          | Valid   | 
    | N          | Y          | N          | N          | Valid   | 
    | N          | N          | Y          | N          | Valid   | 
    | N          | N          | N          | Y          | Valid   | 
    | N          | N          | Y          | Y          | Invalid | 
    

    逻辑是....取 4 列并将它们组合成一个字符串,因此 Y,N,N,N 变为 YNNN。然后替换字母'Y'的所有实例并获得结果的长度。由于您知道原始长度是 4,现在您知道删除了多少个 Y。

    这是计算一个字符串在另一个字符串中出现的次数的经典技巧。

    在我的示例中,我将零或一个 Y 视为有效。

    【讨论】:

      【解决方案4】:

      试试这个:

      DECLARE @Attr TABLE(A1 CHAR,
      A2 CHAR,
      A3 CHAR,
      A4 CHAR)
      
      insert Into @Attr  VALUES('Y','N','N','N')
      insert Into @Attr  VALUES('N','Y','N','N')
      insert Into @Attr  VALUES('N','N','Y','N')
      insert Into @Attr  VALUES('N','N','N','Y')
      insert Into @Attr  VALUES('Y','N','Y','N')
      
      SELECT * FROm @Attr
      
      SELECT * FROM @Attr
      WHERE 
      ((A2<>'Y' AND A3<>'Y' AND A4<>'Y' ) OR 
      (A1<>'Y' AND A3<>'Y' AND A4<>'Y') OR 
      (A1<>'Y' AND A2<>'Y' AND A4<>'Y') OR
      (A1<>'Y' AND A2<>'Y' AND A3<>'Y'))
      

      【讨论】:

        【解决方案5】:

        select 查询中(这似乎足以满足您的目的),那么我建议:

        select t.*
        from t cross apply
             (select count(*) as num_ys
              from (values (attribute1), (attribute2), (attribute3), (attribute4)
                   ) v(attr)
              where attr = 1
             ) v
        where num_ys = 1;
        

        apply在这种情况下的表现其实是相当不错的。更重要的是,这使得泛化查询变得更加简单——添加新属性,或者说至少一个“Y”而不超过 2 个“N”或其他任何内容。

        【讨论】:

          猜你喜欢
          • 2018-01-17
          • 2011-10-24
          • 1970-01-01
          • 2018-01-24
          • 1970-01-01
          • 2012-06-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多