使用SQL从几个位字段中选择具有单个“true”位字段的记录

时间:2017-06-09 16:18:32

标签: mysql sql one-to-many

如果我有这样的表:

CREATE TABLE `Suppression` (
  `SuppressionId` int(11) NOT NULL AUTO_INCREMENT,
  `Address` varchar(255) DEFAULT NULL,
  `BooleanOne` bit(1) NOT NULL DEFAULT '0',
  `BooleanTwo` bit(1) NOT NULL DEFAULT '0',
  `BooleanThree` bit(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`SuppressionId`),
)

是否有一种基于集合的方式,我可以选择所有记录中只有三个位字段之一= 1 而不写出字段名称

例如:

1 10 Pretend Street 1 1 1 
2 11 Pretend Street 0 0 0 
3 12 Pretend Street 1 1 0 
4 13 Pretend Street 0 1 0 
5 14 Pretend Street 1 0 1 
6 14 Pretend Street 1 0 0

我想返回记录4和6.

3 个答案:

答案 0 :(得分:3)

您可以"添加它们":

((lambda (s) (s s -1 1 0))
 (lambda (hep M f! euler-number)
   ((lambda (s)
      (if (= M 20)
          (+ 0.0 euler-number)
          (s s 1 1 (+ euler-number (/ 1 f!)))))
    (lambda (hop N x! euler)
      (hep hop (+ N 1) (* x! N) euler)))))

或者,使用元组:

where cast(booleanone as unsigned) + cast(booleantwo as unsigned) + cast(booleanthree as unsigned) = 1

我不确定你的意思是"基于集合"。

答案 1 :(得分:2)

如果布尔值的数量随着时间的推移而变化,并且您不想更新代码,我建议您将它们设为行而不是列。 例如:

CREATE TABLE `Suppression` (
  `SuppressionId` int(11) NOT NULL AUTO_INCREMENT,
  `Address` varchar(255) DEFAULT NULL,
  `BooleanId` int(11) NOT NULL,
  `BooleanValue` bit(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`SuppressionId`,`BooleanId`),
)

因此,通过1个查询和“分组依据”,您可以检查布尔值的所有值,无论它们多少。当然,这会让你的桌子更大。

编辑:刚出来另一个想法:为什么你没有添加checksum列,其值是所有位的总和?因此,您每次写入表格时都会更新,只需在select

中查看一下即可

答案 2 :(得分:1)

如果你

  1. 必须使用这种表示这些标志的非规范化方式,而你
  2. 必须能够在生产中向您的表中添加新的标记列,并且
  3. 在添加列时无法手动重写查询
  4. 然后你必须弄清楚如何编写程序来编写查询。

    您可以使用此查询来检索布尔值列的结果集,然后您可以在程序中使用该结果集来编写涉及所有这些列的查询。

    SELECT COLUMN_NAME
      FROM INFORMATION_SCHEMA.COLUMNS
     WHERE TABLE_SCHEMA = DATABASE()
       AND TABLE_NAME = 'Suppression'
       AND COLUMN_NAME LIKE 'Boolean%'
       AND DATA_TYPE = 'bit'
       AND NUMERIC_PRECISION=1
    

    不幸的是,当您添加列时,此处提出的方法将以指数方式更加糟糕。任何时候软件工程师说"指数"现在是时候逃避尖叫了。严重。

    更多可扩展的方法是在Suppression行和标志之间建立一对多的关系。添加此表。

    CREATE TABLE SuppressionFlags (
       SuppressionId int(11) NOT NULL,
       FlagName varchar(31) NOT NULL,
       Value bit(1) NOT NULL DEFAULT '0',
       PRIMARY KEY (SuppressionID, FlagName)
    )
    

    然后,当您想要插入带有一些标志变量的行时,请执行以下查询序列。

     INSERT INTO Suppression (Address) VALUES ('some address');
     SET @SuppressionId := LAST_INSERT_ID();
     INSERT INTO SuppressionFlags (SuppressionId,   FlagName,    Value)
                           VALUES (@SuppressionId, 'BooleanOne',   1);
     INSERT INTO SuppressionFlags (SuppressionId,   FlagName,    Value)
                           VALUES (@SuppressionId, 'BooleanTwo',   0);
     INSERT INTO SuppressionFlags (SuppressionId,   FlagName,    Value)
                           VALUES (@SuppressionId, 'BooleanThree', 0);
    

    这为您提供了一个Suppression行,其中SuppressionFlags表中设置了三个标志。请注意使用@SuppressionId在第二个表中设置Id值。

    然后要查找只有一个标志集的所有行,请执行此操作。

     SELECT Suppression.SuppressionId, Suppression.Address
       FROM Suppression
       JOIN SuppressionFlags ON Suppression.SuppressionId = SuppressionFlags.SuppressionId
      GROUP BY Suppression.SuppressionId, Suppression.Address
     HAVING SUM(SuppressionFlags.Value) = 1 
    

    如果你想要更复杂的组合,它会变得有点棘手。例如,如果您想要设置BooleanOneBooleanTwoBooleanThree的所有行,则需要执行以下操作。

    SELECT S.SuppressionId, S.Address
      FROM Suppression S
      JOIN SuppressionFlags A ON S.SuppressionId=A.SuppressionId AND A.FlagName='BooleanOne'
      JOIN SuppressionFlags B ON S.SuppressionId=B.SuppressionId AND B.FlagName='BooleanTwo'
      JOIN SuppressionFlags C ON S.SuppressionId=C.SuppressionId AND C.FlagName='BooleanThree'
     WHERE A.Value = 1 AND (B.Value = 1 OR C.Value = 1)
    

    这种常见的数据库模式称为属性/值模式。因为SQL不容易让你使用变量作为列名(它没有真正反射),这种命名属性的方式是你可扩展性的最佳途径。

    它还有一点SQL。但是你可以在生产中添加任意数量的新标志,而无需重写查询或获得标志匹配的组合爆炸。并且SQL是为处理这种查询而构建的。