Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL计数:不稳定的行为_Sql_Count_Mariadb_Relational Database - Fatal编程技术网

SQL计数:不稳定的行为

SQL计数:不稳定的行为,sql,count,mariadb,relational-database,Sql,Count,Mariadb,Relational Database,我编写的一段SQL的行为与预期不符。一个重要的逻辑是计算有多少客人是VIP,但SQL似乎总是得到错误的答案 以下数据库有6位来宾,其中3位是VIP CREATE TABLE `guest` ( `GuestID` int(11) NOT NULL DEFAULT '0', `fullname` varchar(255) DEFAULT NULL, `vip` tinyint(1) DEFAULT '0', ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我编写的一段SQL的行为与预期不符。一个重要的逻辑是计算有多少客人是VIP,但SQL似乎总是得到错误的答案

以下数据库有6位来宾,其中3位是VIP

CREATE TABLE `guest` (
  `GuestID` int(11) NOT NULL DEFAULT '0',
  `fullname` varchar(255) DEFAULT NULL,
  `vip` tinyint(1) DEFAULT '0',
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `guest`
--

INSERT INTO `guest` (`GuestID`, `fullname`, `vip`) VALUES
(912, 'Sam',  0),
(321, 'Sev', 0),
(629, 'Joe', 0),
(103, 'Tom', 1),
(331, 'Cao', 1),
(526, 'Conor', 1);
最初,SQL返回一个值,表示有5位VIP,这是不正确的,因为只有3位VIP。这是一个相当复杂的数据库,在为这个问题生成一个最小可行的示例时(有一个可重复的错误),脚本现在声明只有2个VIP。同样,这是不正确的

所讨论的SQL是

SELECT slotguest.FK_SlotNo, Count(CASE WHEN guest.vip = 1 THEN 1 END) AS guest_count 
FROM guest 
INNER JOIN slotguest ON guest.GuestID = slotguest.FK_guest 
GROUP BY slotguest.FK_SlotNo;
最慢的结构和内容如下

CREATE TABLE `slotguest` (
  `FK_SlotNo` int(11) NOT NULL,
  `FK_guest` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `slotguest`
--

INSERT INTO `slotguest` (`FK_SlotNo`, `FK_guest`) VALUES
(396, 912),
(396, 321),
(396, 629),
(396, 103),
(396, 331),
(396, 526);

是什么导致Count给出了一个一贯不正确的答案?

正如评论中所指出的(从用户@Fábio Amorim、@Rajat处检查),您的查询似乎按预期进行。由于您在时使用了
大小写设置了一个值,因此最好使用
SUM

如果您将不同VIP类别的计数带到可能存在数据泄漏的位置,可能会更加明显

SELECT guest.vip, slotguest.FK_SlotNo, COUNT(*) AS guest_per_category
FROM guest 
INNER JOIN slotguest ON guest.GuestID = slotguest.FK_guest
GROUP BY guest.vip,slotguest.FK_SlotNo;
闻起来像“爆炸-内爆”。给定

查询是这样执行的:

  • 加入表。假设表的比例不是1:1,这将导致比两个表都多的行
  • 对该临时表进行聚合(例如
    计数
  • 只有这样,
    groupby
    才会收缩到最初所需的行数
  • 解决方案是避免使用包含计数/求和数据的多个表进行聚合。有时这种模式是错误的

     SELECT ...
         FROM ( SELECT x, COUNT(*) AS ct FROM a GROUP BY x ) AS b
         JOIN c ON ...
    

    为了解释问题所在,并给出更接近O.p.询问的答案

    (我假设O.p.是一个错误的简化示例,而实际查询更为复杂。如果我们知道更大的情况,我想我不会那样编写代码。)

    在O.p.查询中,
    如果guest.vip=1,则1 END
    格式不正确。这是一个条件表达式;它应该为查询检索到的所有行返回一个特定值,即
    guest.vip 1
    所在的行

    事实上,行为是没有定义的;正如评论所说,它在某些DBMS上产生了预期的答案;根据O.P.的说法,它不会影响其他人。我猜对于那些产生预期答案的人,DBMS将
    案例
    视为返回
    Null
    ,然后
    计数()
    忽略Null。这是SQL中
    Null
    的一个更可怕的后果

    因此,根据@Fábio Amorim的评论,
    案例需要一个
    ELSE
    ,因此
    Count()
    给出了一个没有帮助的结果,所以让
    ELSE
    返回
    0
    Sum()
    1
    0

    SELECT slotguest.FK_SlotNo, Sum(CASE WHEN guest.vip = 1 THEN 1 ELSE 0 END) AS guest_count 
    FROM guest 
    INNER JOIN slotguest ON guest.GuestID = slotguest.FK_guest 
    GROUP BY slotguest.FK_SlotNo;
    

    对我有用。它显示了
    3
    的计数。请参见尝试更改计数(guest.vip=1时为1结束)
    了解在Maria DB上测试的总和(guest.vip=1时为1结束)
    。对我有用。您的查询不会返回“贵宾人数”。幸运的是,人们能猜出你的意思。使用足够的单词、句子和引用部分例子,清楚、完整地说出你的意思。当给出一个业务关系(ship)/关联或表(base或query result)时,请说明其中的一行根据其列值表示的业务状况。PS在考虑发布之前创建一个。
    SELECT slotguest.FK_SlotNo, Sum(CASE WHEN guest.vip = 1 THEN 1 ELSE 0 END) AS guest_count 
    FROM guest 
    INNER JOIN slotguest ON guest.GuestID = slotguest.FK_guest 
    GROUP BY slotguest.FK_SlotNo;