SQl Abfrage mit COUNT etc

Hallo Liebe User,

ich habe kaum Erfahrung mit SQL, daher bräuchte ich Hilfe bzgl. dieser Aufgabe:

Gegeben sind 3 Tabellen:

Tabelle 1: „Artikel“ mit bspw:
Artikel_id ,
Artikel_Name,

Tabelle 2: „Kategorie“ mit bspw:
Kategorie_id,
Kategorie_Name,
categorie_parent

Tabelle 3: „Artikel_Kategorie“ mit:
Artikel_Kategorie_id,
fk_Artikel_id,
fk_Kategorie_id.

  1. Kann mir jemand die Beziehungen zwischen diesen 3 Tabellen erklären? Warum wird denn zusätzlich die 3. Tabellle erzeugt?

  2. Ich möchte gerne Wissen:

  • Wie viel Artikel existieren,
  • Wie viel Hauptkategorien und Unterkategorien existieren,
  • Die Unterkategien den jeweiligen Hauptkategorien zuordnen-
  • Wie viele Artikel existieren in der jeweiligen Haupt und Unterkategorie
    (Die Anzahl bzw. Summe).

Wie würde das denn als verschachtelte SQL Abfrage aussehen?

Ich bin blutiger Anfäger daher würde ich mich eine schnelle Hilfe sehr sehr sehr freuen!

Viele Grüße,
Water

du hast eine Liste mit Artikel und du hast eine Liste mit Artikelkategorien. Ein Artikel kann in mehreren Kategorieen sein und eine Kategorie kann mehrere Artikel beinhalten. Dieses „Problem“ wird als M-N Problematik angeschaut. Dies muss man mit Hilfe einer Hilfstabelle (in diesem Fall Artikel_Kategorie) lösen. In dieser Hilfstabelle werden dann Artikel und Kategorien miteinander verbunden. WICHTIG dabei ist, dass ein Artikel mehreren Kategorieen angehören kann. Ansonsten würde das keinen Sinn machen.

Jetzt zu den Abfragen:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[Artikel]’) AND type in (N’U’))
DROP TABLE [dbo].[Artikel]

create Table Artikel
(
Artikel_ID int not null,
Artikel_Name nvarchar (50)
)

insert into Artikel (Artikel_ID, Artikel_Name)
values
(1, ‚Cola‘),
(2, ‚Stilles Wasser‘),
(3, ‚Wein‘),
(4, ‚Hot dog‘)

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[Kategorie]’) AND type in (N’U’))
DROP TABLE [dbo].[Kategorie]

create Table Kategorie
(
Kategorie_ID int not null,
categorie_parent_ID int null,
Kategorie_Name nvarchar(50)
)

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N’[dbo].[Artikel_Kategorie]’) AND type in (N’U’))
DROP TABLE [dbo].[Artikel_Kategorie]

insert into Kategorie (Kategorie_ID, categorie_parent_ID, Kategorie_Name)
values
(1, NULL, ‚Kategorie Getränk‘),
(2, 1, ‚Subkategorie Süssgetränk‘),
(3, 1, ‚Subkategorie Wasser‘),
(4, 1, ‚Subkategorie Alkoholische Getränke‘),
(5, NULL, ‚Kategorie Esswaren‘)

create table Artikel_Kategorie
(
Artikel_Kategorie_ID int not null,
fk_Artikel_ID int not null,
fk_Kategorie_ID int not null
)

insert into Artikel_Kategorie (Artikel_Kategorie_ID, fk_Artikel_ID, fk_Kategorie_ID)
values
(1, 1, 1), – cola ist ein Getränk
(2, 1, 2), – cola ist ein Süssgetränk
(3, 2, 1), – Wasser ist ein Getränk
(4, 2, 2), – Wasser ist ein Getränk
(5, 3, 1), – Wein ist ein Getränk
(6, 3, 3), – Wein ist ein Alkoholisches Getränk
(7, 4, 5) – Hot dog ist etwas zum Essen

– Anzahl Artikel
select COUNT(*) from Artikel

– Anzahl Kategorien
select COUNT(*) from Kategorie – macht so aber nur beschränkt sinn

– Anzahl Hauptkategorien
select COUNT(*) from Kategorie where categorie_parent_ID is null

– pro Kategorie die Anzahl Artikel ausweisen
select
Kategorie.Kategorie_Name
,COUNT(Artikel_Kategorie.fk_Artikel_ID) [Anzahl Artikel]
from Artikel_Kategorie
inner join Kategorie on Artikel_Kategorie.fk_Kategorie_ID = Kategorie.Kategorie_ID
group by Kategorie.Kategorie_Name

– jetzt noch die letzte Variante
select
Kategorie.Kategorie_Name
,CASE
WHEN Kategorie.categorie_parent_ID IS null then N’Hauptkategorie’
ELSE ‚Unterkategorie‘
END [Type]
,COUNT(Artikel_Kategorie.fk_Artikel_ID) [Anzahl Artikel]
from Artikel_Kategorie
inner join Kategorie on Artikel_Kategorie.fk_Kategorie_ID = Kategorie.Kategorie_ID
group by Kategorie.Kategorie_Name, Kategorie.categorie_parent_ID

  1. Kann mir jemand die Beziehungen zwischen diesen 3 Tabellen erklären? Warum wird denn zusätzlich die 3. Tabellle erzeugt?

In Tabelle 1 sind alle Produkte
In Tabelle 2 sind alle Kategorien
In Tabelle 3 sind Produkte und Kategorien verknüpft. Es kann also zum Beispiel sein, dass das Produkt mit Artikel_id=10 mehrmals - z.B. 3x - in Tabelle3 vorkommt.

Artikel_Kategorie_id | fk_Artikel_id | fk_Kategorie_id

101 | 10 | 3
102 | 10 | 7
103 | 10 | 15

Das Produkt ist also den Kategorien 3, 7 und 15 zugewiesen.


  1. Ich möchte gerne Wissen:
  • Wie viel Artikel existieren,
    SELECT COUNT(*) FROM Artikel;

  • Wie viel Hauptkategorien und Unterkategorien existieren,
    … Anzahl aller Kategorien anzeigen:
    SELECT COUNT(*) AS anzahl FROM Kategorie;

… Anzahl Hauptkategorien:
SELECT COUNT(*) AS anzahl FROM Kategorie WHERE categorie_parent = 0;

… Anzahl Unterkategorien:
SELECT COUNT(*) AS anzahl FROM Kategorie WHERE categorie_parent > 0;

  • Die Unterkategien den jeweiligen Hauptkategorien zuordnen-

SELECT h.Kategorie_Name, COUNT(u.*) as anzahl_unterkategorien
FROM Kategorie h
INNER JOIN Kategorie u ON u.categorie_parent = h.Kategorie_id
GROUP BY h.Kategorie_id;

  • Wie viele Artikel existieren in der jeweiligen Haupt und Unterkategorie:

SELECT k.Kategorie_Name, COUNT(p.*) as anzahl_produkte
FROM Kategorie k
INNER JOIN Artikel_Kategorie x ON x.fk_Kategorie_id = k.Kategorie_id
INNER JOIN Artikel p ON x.fk_Artikel_id = k.Artikel_id
GROUP BY k.Kategorie_id
ORDER BY k.categorie_parent ASC, k.Kategorie_id ASC;

Das Gleiche könnte man auch so schreiben:
SELECT k.Kategorie_Name, COUNT(p.*) as anzahl_produkte
FROM Kategorie k, Artikel_Kategorie x, Artikel p
WHERE x.fk_Kategorie_id = k.Kategorie_id AND x.fk_Artikel_id = k.Artikel_id
GROUP BY k.Kategorie_id
ORDER BY k.categorie_parent ASC, k.Kategorie_id ASC;

Viel Erfolg!

Miran Melansek

Hallo Water,

zu Frage 1:

Die Tabelle 1 (Artikel) und die Tabelle 2 (Kategorie) sind als Hilfstabellen anzusehen. Die Tabelle 3 ist die Haupttabelle (führend). Zu erkennen ist dies anhand des Präfix fk (Fremdkeys).

zu Frage 2:

mit diesem SQL-Statement müsstest du auch die anderen Fragestellungen in den Griff bekommen:

SELECT Kategorie.Kategorie_Id, Count(*) AS AnzArtikel
FROM Artikel_Kategorie, Artikel, Kategorie
WHERE (((Artikel_Kategorie.fk_Artikel_id)=[Artikel].[Artikel_id]) AND ((Artikel_Kategorie.fk_Kategorie_id)=[Kategorie].[Kategorie_id]))
GROUP BY Kategorie.Kategorie_Id;

Das SQL-Statement beantwortet die letzte Frage: Anzahl Artikel zur jeweiligen Kategorie.

Entsprechend musst du lediglich den Group by anpassen, um die ersten Fragen beantworten zu können.

schönen Gruß aus dem Berchtesgadener Land
Stefan Klinger

PS: Der Syntax stammt aus MS Access.

leichter lesbar ist dieses SQL-Statement:

SELECT
a.fk_Kategorie_id ,
c.Kategorie_name,
count(*)
FROM Artikel_Kategorie a,
Artikel b,
Kategorie c

WHERE a.fk_Artikel_id = b.Artikel_id
AND a.fk_Kategorie_id = c.Kategorie_id

GROUP BY
a.fk_Kategorie_id,
c.Kategorie_name,

Hallo Water,

irgendwie denke ich nicht, dass wir dafür da sind Deine Aufgaben (aus dem Studium oder Lehre) zu lösen, daher wird es von mir auch keine kmplette Lösung geben, aber vieleicht reichen Dir ja auch schon folgende Aussagen und Hinweise:

  • die dritte Tabbelle dient der Verknüpfung der Daten von Tabelle 1 und 2, also damit man rauskriegen kann welche Artikel gehören zu welcher Kategorie

  • Hat eine Kategorie eine Elternkategorie, wird es sich wohl um eine Unterkategorie handeln

  • Mit einer einzigen Abfrage wirst Du das alles sicher abfragen können, außer Du stehst auf redundante Informationen

VG Volkmar

Man benutzt eine gesonderte Verknüfungstabelle, wenn man m:n-Beziehungen abbilden möchte. Ein Artikel kann in mehreren Kategorien zugordnet werden, indem mehrere Sätze mit der einen fk_Artikel_id und verschiedenen fk_Kategorie_id eingetragen werden.

Die Verknüpfüng zur Parent_Kategorie sollte nicht über den Namen der Kategorie erfolgen, weil es dann keine beliebigen Baumstrukturen geben darf, sondern jeder Knoten muss einen für sich eindeutigen Namen haben.

Wenn wir annehmen, hier steht die Id der übergeordneten kategorie oder nil, wenn es keine übergeordnete gibt, dann erhält man die Anzahl der Hauptkategorien so:
select count(*) from kategorie where parent_Kategorie is nil;

Die Gesamtzahl der Kategorien erhält man einfach, indem die where-Klausle weggelassen wird.

Die Anzahl der Artikel ist:
select count(*) from Artikel;

Die Anzahl der Unterkategorieen auf der ersten untergeordneten Ebenen je Hauptkategorie erhält man so:

select hk.Kategorie_Name, count(uk.Kategorie_id) from kategorie hk, kategorie uk where uk.categorie_parent
= hk.Kategorie_id and hk.categorie_parent is nil
group by hk.Kategorie_Name

Die Anzahl der Artikel je Kategorie ist sehr schwer mit sql zu ermitteln, weil die Artikel erstens mehrfach zugeordnet sein können, aber nicht mehrfach gezählt werden sollten und weil für jede Ebene ein weiteres Mal die Kategorientabelle verknüpft werden muss.

Mein Lösungsansatz lautet:

  1. stelle die maximale Anzahl Hierarchie-Ebenen fest.
  2. Baue eine Tabelle „Hierarchie-Baum“ auf, in dem jede Kategorie bis zu seiner Wurzel aufgelöst steht.
  3. Ordne jeder Kategorie seinen Abstammungspfad zu.
  4. Die Zahl der Artikel je Hauptkategorie ist dann:
    select b.wurzel, count (distinct a.artikel_ID)
    from artikel a, kategorie k, stammbaum b
    where a.kategorie_id = k.kategorie_id
    and k.stammbaum_id = b.id
    group by b.wurzel

Das ist noch nicht ganz ausgearbeitet. Wenn Sie eine bessere Lösung finden, wäre ich daran interessiert.
Gruß
Karl G

Hallo Water,

die Beziehung zwischen den Tabellen sollte eine eindeutige ID-Spalte (Artikel-ID etc.) in jeder Tabelle sein. Um jetzt einem Artikel eine Kategorie zuorden zu können, sollte in der Tabelle Artikel eine Spalte Kategorie-ID existieren. Anhand dieser Kategorie-ID kann man nun in der Tabelle Kategorie nachschauen, welche Kategorie sich hinter eben dieser Kategorie-ID verbirgt. Diese Tabellen können dann über diese ID mit dem JOIN-Befehl inerhalb einer SELECT-Abfrage verbunden werden.

Könnte mir vorstellen, dass Kategorie und Artikel-Kategorie zwei verschiedene Sachen (Haupt- und Untergategorie) sind.

Anzahl Artikel (berücksichtigt keine doppelte oder gelöschte Artikel):
Select count(Artikel-ID) as AnzahlArtikel from artikel

Das gleiche kannst Du mit den anderen Tabellen machen.

Summen berechen:
Select sum(Preis) as Summe from artikel

Gruß
Michael

Hallo Water

(War auf Osterurlaub, daher etwas späte Antwort.)

Hm, Hausaufgaben nicht gemacht ?
Es hat wenig Sinn, die Lösung solcher Probleme von anderen machen zu lassen anstatt sich selber mit dem Thema zu beschäftigen.
Im Internet gibts haufenweise kostenlose Tutorials zu relationalen Datenbanken und SQL, man muss sich natürlich die Mühe machen und sich was anschauen.

Als Hilfe zur Einführung beantworte ich aber trotzdem deine erste Frage:

Es gibt eine Tabelle ‚Artikel‘, in der die Artikel (mit eindeutiger ID) gespeichert sind.
Dann gibt es eine Tabelle ‚Kategorien‘, in der die Artikelkategorien (mit eindeutiger ID) gespeichert sind.

Nun kann jeder Artikel zu einer oder mehreren Kategorien gehören, des weiteren gehört zu jeder Kategorie ein oder mehrere Artikel.
Es handelt sich also um eine m:n-Beziehung zwischen den Artikeln und den Kategorien.
Man braucht also eine Datei, in der jede Verknüpfung eines Artikels mit einer Kategorie gespeichert ist. Jeder Eintrag dort besteht aus einer Artikel-ID und einer Kategorie-ID um auszudrücken das dieser Artikel zu dieser Kategorie gehört. Wenn ein Artikel zu mehreren Kategorien gehört muss für jede dieser Verknüpfungen ein Eintrag angelegt werden.
Z.B.:

Artikel\_id Kategorie\_id
 3 8
 3 12
 3 13
 5 12
 8 13
 8 16

Das heisst:
Artikel 3 gehört zu Kategorie 8, 12 und 13
Artikel 5 gehört zu Kategorie 12
Artikel 8 gehört zu Kategorie 13 und 16
Das heisst umgekehrt:
Zu Kategorie 8 gehört der Artikel 3
Zu Kategorie 12 gehört der Artikel 3 und 5
Zu Kategorie 13 gehört der Artikel 3 und 8
Zu Kategorie 16 gehört der Artikel 8

mfg
Christof

Hallo,
vielleicht solltest Du Dich erst mal mit dem Normalisieren von Tabellen beschäftigen. Dann wird Dir auch klar wofür die dritte Tabelle ist. Es geht in einer relationalen Datenbank darum keine redundanten Daten zu speichern. Das erreicht man durch Normalisieren. Die dritte Tabelle stellt durch fk_ (Foreign Key = Fremdschlüssel) eine Beziehung zu Tabelle 1 und 2 her.

Beispiel zu 2a) Select count (*) from artikel -> wenn man annimmt, dass da jeder Artikel einmal drin steht.
Beziehungen zu den Tabellen stellt man mit Joins dar. Beispiel: Select * from artikel, kategorie, artikel_kategorie where artikel.artikel_id = artikel_kategorie.fk_artikel and kategorie.kategorie_id = artikel_kategorie.fk_kategorie_id -> somit hast Du die drei Tabellen miteinander verknüpft. Oder mit Ansii-Joins wenn es evtl. keine Oracle-Datenbank ist. Select * from artikel inner join artikel_kategorie on artikel.artikel_id = artikel_kategorie.fk_artikel_id -> hier hast Du schon mal zwei Tabellen verknüpft. Die dritte mit einem weiteren inner join …

Hallo Water,

sorry für die späte Antwort, ich habe die Frage offensichtlich übersehen :frowning:

zu 1) Die dritte Tabelle - eine sogenannte Intersection-Tabelle - benötigst du um eine m:n-Beziehung zwischen Artikeln und Kategorien aufbauen zu können. Ein Artikel kann mehreren Kategorien zugeordnet sein und mehrere Artikel einer Kategorie.

zu 2) Select count(*) from Artikel gibt dir die Anzahl aller Artikel
Select count (*) from Artikel_kategorie where categrie_parent is null gibt die Anzahl der Hauptkategorien - Unterkategorien entsprechen mit is not null

select hkat.kategorie_name „Hauptkategorie“, count (distinct artkat.fk_artikel_id) „Anzahl“
from dh_Kategorie hkat, dh_Kategorie ukat , dh_Artikel_kategorie artkat
where hkat.categorie_parent is null
and ukat.categorie_parent = hkat.kategorie_id
and (artkat.fk_kategorie_id = hkat.kategorie_id OR artkat.fk_kategorie_id=ukat.kategorie_id)
group by hkat.kategorie_name

Gibt dir die Anzahl pro Hauptkategorie (inklusive der Artikel die zur Unterkategorie zugeordnet sind). Die Anzahl je Unterkategorie solltest du dir daraus selber ableiten können