2016-04-05 19 views
-1

Meine Datenbanken beteiligt aussehen wie so:SQL Query - Abfragen AVG von COUNT beteiligt und Abfragen Termine

PEAK (NAME, ELEV, DIFF, MAP, REGION)
BERGSTEIGER (Name, Geschlecht)
TEILGENOMMEN (trip_id, NAME)
geklettert (trip_id, PEAK, WENN)

  • PEAK gibt Informationen über die Berggipfel, die der Benutzer interessiert. Die Tabelle listet den Namen jedes Gipfels auf, seine Höhe (in ft), seinen Schwierigkeitsgrad (auf einer Skala von 1-5), die Karte, die er ist lokalisiert auf und die Region der Sierra Nevada, in der es sich befindet.
  • CLIMBER listet die Mitglieder des Vereins auf und gibt ihren Namen und Geschlecht an.
  • PARTICIPATED gibt die Gruppe von Kletterern an, die an den verschiedenen Klettertouren teilgenommen haben. Die Anzahl der Teilnehmer in jeder Reise variiert.
  • CLIMBED gibt an, welche Gipfel auf jeder Kletterroute erklommen wurden, zusammen mit den Daten, mit denen jeder Gipfel erklommen wurde.

Ich brauche Hilfe w/eine SQL-Abfrage für diese 2 Beispielszenarien zu schreiben:

  • Berechnen Sie die durchschnittliche Anzahl der Spitzen von den Männern in dem Verein und von den Frauen in dem Club skaliert.
  • Welche Leute haben jeden einzelnen Gipfel bestiegen, den Maria bestiegen hat?
  • Wer hat in etwa 60 Tagen mehr als 20 Gipfel erklommen?

EDIT: Erste Abfrage funktioniert jetzt und sieht wie folgt aus:

SELECT SEX, AVG(num_peaks) AS avg_peaks 
FROM 
    (
    SELECT CLIMBER.*, COUNT(CLIMBED.PEAK) num_peaks 
    FROM CLIMBED 
    INNER JOIN PARTICIPATED 
    ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID 
    RIGHT OUTER JOIN CLIMBER 
    ON CLIMBER.NAME = PARTICIPATED.NAME 
    GROUP BY CLIMBER.NAME, CLIMBER.SEX 
) 
GROUP BY SEX; 

Diese Abfrage mir die Gesamtzahl der Spitzen gibt stieg mein Männchen und Weibchen. Aber ich kann nicht herausfinden, wie man die Mittelwerte anstelle der Zählungen erhält. Ich weiß, dass Sie nicht einfach die COUNT-Funktion zu AVG b/c ändern können, meine Daten sind in der Zeichenfolge-Form und nicht Integer.

Meine zweite Abfrage sieht so aus:

SELECT DISTINCT PARTICIPATED.NAME 
FROM PARTICIPATED 
INNER JOIN CLIMBED 
ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID 
WHERE CLIMBED.PEAK IN 
    (
    SELECT CLIMBED.PEAK 
    FROM CLIMBED 
    INNER JOIN PARTICIPATED 
    ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID 
    WHERE NAME IN ('MARIA') 
    ) 
AND PARTICIPATED.NAME NOT IN ('MARIA'); 

Die Abfrage gibt mir all die Menschen, die einen Höhepunkt erklommen haben, dass Maria auch geklettert, aber gibt mir nicht nur die Menschen, die geklettert alle einzigen Gipfel, den Maria bestiegen hat. Nicht sicher, wie man den Rest der Leute auf diese Art herausfiltert.

Und schließlich meine letzte Abfrage sieht so aus:

SELECT PARTICIPATED.NAME, COUNT(DISTINCT CLIMBED.PEAK) 
FROM PARTICIPATED 
LEFT JOIN CLIMBED 
ON CLIMBED.TRIP_ID = PARTICIPATED.TRIP_ID 
GROUP BY PARTICIPATED.NAME; 

Diese Abfrage alle der Bergsteiger Namen gibt und die Gesamtzahl der Spitzen, die sie haben jeweils geklettert, aber ich habe keine Ahnung, wie es zu filtern noch mehr, so dass es nur Leute zeigt, die innerhalb von 60 Tagen mehr als 20 Gipfel erklommen haben. Ich versuchte

HAVING CLIMBED.WHEN BETWEEN -60 AND 60; 

verwenden, aber das funktioniert nicht.

Jede Hilfe wird sehr geschätzt, und ich verwende Oracle Express als meine DB.

+1

Sie haben diese Frage bereits gestellt [hier] (http://stackoverflow.com/questions/36437653/sql-query-average-climbed-and-pair-that-has-climbed-the-most-peaks) – MT0

+0

Keine Antwort auf deine ganze Frage. Aber Ihre zweite Abfrage sollte 'WHERE CLIMBED.PEAK = ALL (... WO NAME = 'MARIA') UND NAME <> 'MARIA' 'haben. Die Verwendung von "IN" entspricht = ANY (...), aber Sie benötigen alle Peaks, nicht nur einen. Außerdem ist es sinnlos, IN für einzelne Werte zu verwenden, stattdessen = und <>. Und Sie haben ein zusätzliches Semikolon. Siehe [dieser Beitrag über ORACLE und ANY, ALL und SOME] (https://oracle-base.com/articles/misc/all-any-some-comparison-conditions-in-sql). –

Antwort

0

Ich präzise ich arbeite auf SQL-Server, so suchte ich im Internet nach Oracle-Syntax, könnte es einige Fehler geben, aber ich denke, es ist in Ordnung.

In Bezug auf Ihre erste Anfrage wäre meine Idee, eine Unterabfrage zu machen, die die Anzahl der von jedem Teilnehmer gekletterten Spitzen zählt und dann den Durchschnitt für jedes Geschlecht annimmt. Ich verwende die with Syntax so klar wie möglich, um die Unterabfrage zu trennen.

Dann, in Bezug auf Ihre zweite Abfrage, würde ich es anders denken. Ich hatte einen Tisch mit jedem Kletterer und eine Linie für jede Grube, die Maria bestiegen hat. Wenn eine Grube, die Maria bestiegen hat, nicht vom Kletterer bestiegen wird, dann hätte eine Spalte 1 als Wert, sonst 0. Wenn die Summe Null ist, kletterte der Kletterer alle Gipfel, die Maria erklommen hatte.

Zuerst wählen wir jede Grube aus, die Maria bestiegen hat, und in einer anderen Tabelle klettert jeder Gipfel durch andere, dann benutzen Sie einen LEFT JOIN, um sich ihnen anzuschließen; Ich weiß nicht, ob Sie wissen, wie es funktioniert, aber es würde einen Wert geben, wenn der Peak nicht bestiegen wurde, wonach wir suchen. Es wird nur Gipfel geben, die von Maria bestiegen werden, nicht die anderen. Ich benutze die Gruppe von TABLE_PARTICIPER, um zu viele Zeilen zu vermeiden, aber es ist nicht notwendig.

WITH TABLE_MARIA AS 
(
SELECT CLIMBED.PEAK 
FROM CLIMBED 
INNER JOIN PARTICIPATED 
ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID 
WHERE NAME IN ('MARIA') 
), 

TABLE_PARTICIPER AS 
( 
SELECT CLIMBED.PEAK, 
NAME 
FROM CLIMBED 
INNER JOIN PARTICIPATED 
ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID 
WHERE NAME NOT IN ('MARIA') 
GROUP BY NAME, 
CLIMBED.PEAK 
) 

Jetzt wil ich die Tabelle mit jeder von Maria stieg Spitzenunterabfrage, jeder Name von anderen participers und die Spitze, wenn sie es geklettert, NULL wenn sie es nicht taten, und sie dann wählen Sie mit der Funktion aufweist.

SELECT NAME 
FROM (
SELECT TABLE_MARIA.PEAK AS MARIA_PEAK, 
TABLE_PARTICIPER.PEAK AS PARTICIPER_PEAK, 
TABLE_PARTICIPER.NAME 
FROM TABLE_MARIA 
LEFT JOIN TABLE_PARTICIPER ON TABLE_MARIA.PEAK = TABLE_PARTICIPER.PEAK 
) AS QUERY 
GROUP BY NAME HAVING SUM(CASE WHEN PARTICIPER_PEAK IS NULL THEN 1 ELSE 0 END) = 0 

Und das sollte perfekt funktionieren. Sag mir, wenn es ein Problem gibt.

In Bezug auf die letzte Abfrage können wir etwas "schmutzig" tun. Nehmen wir einen Tisch mit jedem Kletterer, jeder Gipfel, den sie zu jedem Zeitpunkt bestiegen haben, und links mit sich selbst, um für jeden Bergsteiger viele Reihen zu haben, um zu wissen, wie viele Gipfel er in den 60 Tagen vor diesem Datum bestiegen hat . dann können wir für jeden Bergsteiger zählen und das Datum, die Anzahl der Zeilen und für die der Zählung Vorgesetzter von 20.

WITH TABLE_PEAKS AS 
(
SELECT CLIMBED.PEAK, 
CLIMBED.WHEN, 
PARTICIPATED.NAME 
FROM CLIMBED 
INNER JOIN PARTICIPATED 
ON PARTICIPATED.TRIP_ID = CLIMBED.TRIP_ID 
) 

SELECT DISTINCT NAME 
FROM (
SELECT T1.NAME 
FROM TABLE_PEAKS T1 
LEFT JOIN TABLE_PEAKS T2 ON T1.NAME = T2.NAME AND 
(T2.WHEN > T1.WHEN OR (T2.WHEN=T1.WHEN AND T2.PEAK <>T1.PEAK)) 
AND NOT (T2.WHEN > ADDDATE(T1.WHEN,60)) 
) AS QUERY 
GROUP BY NAME 
HAVING COUNT(*) > 20 

Sag mir nur Kletterer nehmen, wenn Sie Probleme haben!

+0

Ich habe jetzt die erste herausgefunden, aber die zweite Frage Ich bin nicht sicher, wie Sie Ihre Antwort zusammenfügen, um eine funktionierende Abfrage dafür zu bekommen. –

+0

Oups, sorry, ich habe ein Komma zwischen den beiden mit Klauseln vergessen, meine Antwort ist bearbeitet. Es tut uns leid ! – BD01

+0

Ich habe eine Frage zu Ihrer dritten Frage, meinen Sie Leute, die 20 verschiedene Gipfel in 60 Tagen erklommen haben, oder 20 Gipfel, sogar wenn es 3 mal den gleichen Gipfel gibt? Und ist es 60 Tage oder 120 Tage (60 Tage vor oder nach einem bestimmten Datum)? – BD01