2009-09-04 22 views
10

Ich habe eine Tabelle, die mehrere Beziehungen zu anderen Beziehungen mit anderen Tabellen hat. Nehmen wir an, der Haupttisch ist eine Person und die anderen Tische repräsentieren Haustiere, Autos und Kinder. Ich möchte eine Abfrage, die Details der Person, die Anzahl der Haustiere, Autos und Kinder gibt sie z.SQL-Abfrage zu zählen() mehrere Tabellen

 
Person.Name Count(cars) Count(children) Count(pets) 

John Smith 3   2    4 
Bob Brown  1   3    0 

Was ist der beste Weg, dies zu tun?

Antwort

6

Subquery Factoring (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 

Mit Inline-Ansichten:

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 
0

Beachten Sie, dass es auf Ihrem Geschmack von RDBMS abhängt, ob es verschachtelte wählt wie folgt unterstützt:

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, das funktioniert zumindest mit PostgreSQL und MSSQL. Nicht getestet, daher kann Ihre Laufleistung variieren.

+0

Dieses * sollte * in Oracle funktionieren - ich habe es nicht getestet –

+2

Dies ist die einfachste Lösung, würde aber aufgrund der korrelierten Unterabfragen wahrscheinlich zu einer schlechten Leistung führen. Wenn Ihre Datenbank jedoch klein ist, spielt dies keine Rolle. –

+0

interessant zu sehen, dass Sie Ihre technische Antwort geben Ihren persönlichen Geschmack;) – paweloque

0

Subselects Mit nicht sehr gut Praxis kann aber sein, hier wird es gut sein

 
select p.name, (select count(0) from cars c where c.idperson = p.idperson), 
       (select count(0) from children ch where ch.idperson = p.idperson), 
       (select count(0) from pets pt where pt.idperson = p.idperson) 
    from person p 
0

Sie können dies tun, mit drei Outer-Joins:

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 

Ich glaube, dass Oracle unterstützt jetzt die case when Syntax, aber wenn nicht, könnten Sie eine Decodierung verwenden.

+0

Oracle hat CASE-Anweisungen seit 9i unterstützt. –

+0

Rexem, Danke für die Klarstellung! Ich habe einige böse Decode-Aussagen geschrieben und wäre gerne in der Lage gewesen, die Case-Anweisung zu verwenden! Doug. –

+0

Sie können auch einfach count (cars.id) usw. verwenden. Es werden keine Nullwerte gezählt. –

1

Ich würde wahrscheinlich es wie folgt tun:

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 
-1

Sie müssen mehr Zähler Anweisungen in der Abfrage. Aus der Spitze von meinem Kopf,

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 
5

könnten Sie die COUNT(distinct x.id) Synthax verwenden:

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 
+0

Für dieses gewählt, weil es sehr einfach ist. – jvangeld