SQL查询Count()多个表

Posted

技术标签:

【中文标题】SQL查询Count()多个表【英文标题】:SQL Query to Count() multiple tables 【发布时间】:2009-09-04 14:47:12 【问题描述】:

我有一个表,它与其他表有几个一对多的关系。假设主表是一个人,其他表代表宠物、汽车和儿童。我想要一个返回此人详细信息的查询,例如他们拥有的宠物、汽车和孩子的数量。

Person.Name 计数(汽车) 计数(儿童) 计数(宠物) 约翰史密斯3 2 4 鲍勃布朗 1 3 0

最好的方法是什么?

【问题讨论】:

【参考方案1】:

子查询分解 (9i+):

WITH count_cars AS (
    SELECT t.person_id
           COUNT(*) num_cars
      FROM CARS c
  GROUP BY t.person_id),
     count_children AS (
    SELECT t.person_id
           COUNT(*) num_children
      FROM CHILDREN c
  GROUP BY t.person_id),
     count_pets AS (
    SELECT p.person_id
           COUNT(*) num_pets
      FROM PETS p
  GROUP BY p.person_id)
   SELECT t.name,
          NVL(cars.num_cars, 0) 'Count(cars)',
          NVL(children.num_children, 0) 'Count(children)',
          NVL(pets.num_pets, 0) 'Count(pets)'
     FROM PERSONS t
LEFT JOIN count_cars cars ON cars.person_id = t.person_id
LEFT JOIN count_children children ON children.person_id = t.person_id
LEFT JOIN count_pets pets ON pets.person_id = t.person_id

使用内联视图:

   SELECT t.name,
          NVL(cars.num_cars, 0) 'Count(cars)',
          NVL(children.num_children, 0) 'Count(children)',
          NVL(pets.num_pets, 0) 'Count(pets)'
     FROM PERSONS t
LEFT JOIN (SELECT t.person_id
                  COUNT(*) num_cars
             FROM CARS c
         GROUP BY t.person_id) cars ON cars.person_id = t.person_id
LEFT JOIN (SELECT t.person_id
                  COUNT(*) num_children
             FROM CHILDREN c
         GROUP BY t.person_id) children ON children.person_id = t.person_id
LEFT JOIN (SELECT p.person_id
                  COUNT(*) num_pets
             FROM PETS p
         GROUP BY p.person_id) pets ON pets.person_id = t.person_id

【讨论】:

【参考方案2】:

您可以使用COUNT(distinct x.id) 合成器:

SELECT person.name, 
       COUNT(DISTINCT car.id) cars, 
       COUNT(DISTINCT child.id) children, 
       COUNT(DISTINCT pet.id) pets
  FROM person
  LEFT JOIN car ON (person.id = car.person_id)
  LEFT JOIN child ON (person.id = child.person_id)
  LEFT JOIN pet ON (person.id = pet.person_id)
 GROUP BY person.name

【讨论】:

投了这个票,因为它非常简单。【参考方案3】:

我可能会这样做:

SELECT Name, PersonCars.num, PersonChildren.num, PersonPets.num
FROM Person p
LEFT JOIN (
   SELECT PersonID, COUNT(*) as num
   FROM Person INNER JOIN Cars ON Cars.PersonID = Person.PersonID
   GROUP BY Person.PersonID
) PersonCars ON PersonCars.PersonID = p.PersonID
LEFT JOIN (
   SELECT PersonID, COUNT(*) as num
   FROM Person INNER JOIN Children ON Children.PersonID = Person.PersonID
   GROUP BY Person.PersonID
) PersonChildren ON PersonChildren.PersonID = p.PersonID
LEFT JOIN (
   SELECT PersonID, COUNT(*) as num
   FROM Person INNER JOIN Pets ON Pets.PersonID = Person.PersonID
   GROUP BY Person.PersonID
) PersonPets ON PersonPets.PersonID = p.PersonID

【讨论】:

【参考方案4】:

请注意,这取决于您的 RDBMS 风格,是否支持嵌套选择,如下所示:

SELECT p.name AS name
   , (SELECT COUNT(*) FROM pets e WHERE e.owner_id = p.id) AS pet_count
   , (SELECT COUNT(*) FROM cars c WHERE c.owner_id = p.id) AS world_pollution_increment_device_count
   , (SELECT COUNT(*) FROM child h WHERE h.parent_id = p.id) AS world_population_increment
FROM person p
ORDER BY p.name

IIRC,这至少适用于 PostgreSQL 和 MSSQL。未经测试,因此您的里程可能会有所不同。

【讨论】:

这是最简单的解决方案,但由于相关子查询可能会导致性能不佳。但是,如果您的数据库很小,则可能无关紧要。 很高兴看到你给出你的技术答案你的个人风格;) @Eric:你是对的,但是,数据库可能会重写这个语句。所以最终它可能会成为你所提议的。 睡眠不足会导致失去自制力:-)【参考方案5】:

使用子选择不是很好的做法,但可能在这里会很好

select p.name, (select count(0) from cars c where c.idperson = p.idperson), (从子 ch 中选择 count(0),其中 ch.idperson = p.idperson), (从宠物 pt 中选择 count(0),其中 pt.idperson = p.idperson) 来自人 p

【讨论】:

【参考方案6】:

你可以用三个外连接来做到这一点:

SELECT
    Person.Name,
    sum(case when cars.id is not null then 1 else 0 end) car_count,
    sum(case when children.id is not null then 1 else 0 end) child_count,
    sum(case when pets.id is not null then 1 else 0 end) pet_count
FROM
    Person
LEFT OUTER JOIN
    cars on
    Person.id = cars.person_id
LEFT OUTER JOIN
    children on
    Person.id = children.person_id
LEFT OUTER JOIN
    pets on
    Person.id = pets.person_id
GROUP BY
    Person.Name

我相信 Oracle 现在支持 case when 语法,但如果不支持,您可以使用解码。

【讨论】:

Oracle 从 9i 开始就支持 CASE 语句。 Rexem,感谢您的澄清!我写了一些讨厌的解码语句,并且很想能够使用 case 语句!道格。 你也可以只使用count(cars.id)等,它不会计算空值。【参考方案7】:

您需要在查询中包含多个计数语句。在我的脑海中,

SELECT  p.Name, COUNT(DISTINCT t.Cars), COUNT(DISTINCT o.Children), Count(DISTINCT p.Pets)
FROM Person p
INNER JOIN Transport t ON p.ID = t.PersonID
LEFT JOIN Offspring o ON p.ID = o.PersonID
LEFT JOIN Pets p ON p.ID = o.OwnerID
GROUP BY p.Name
ORDER BY p.Name

【讨论】:

以上是关于SQL查询Count()多个表的主要内容,如果未能解决你的问题,请参考以下文章

sql count(*) 查询另一个执行多个结果的查询的结果

ORACLE怎么用SQL查询多张表和多个时间点的数据的行数?

sql 查询某一字段值的个数

sql一个表中同时查询两个count的sql语句

单个 SQL 查询中的多个计数

SQL 查询记录数的SQL语句