2017-04-20 2 views
0

Ich bin neu in dieser SQL-Welt. Nachdem ich ein Entwickler mit begrenzten Kenntnissen in SQL bin & einfache verbindet. Ich habe ein Problem beim Schreiben von SQL-Join für Eins-zu-viele-Beziehung. Hier ist mein Problem sagen -1 zu viele mit Statusüberprüfung auf vielen Seiten

Zum Beispiel, wenn ich einen Kunden Tisch mit:

id Name   address 
1 manoj  Japan 
2 Sunil  US 

Und ein Ticket Tisch mit:

id customerid  ticketstatus 
1 1    closed 
2 1    closed 
3 2    closed 
4 1    open 
5 2    closed 

Nun, was ich will nach Join ist:

id  customername  ticketstatus 
2   sunil   closed 

Also ich möchte nur die Kunden, die alle Tickets Status wurde geschlossen.

Kann mir bitte jemand schriftlich helfen?

Antwort

1

Bitte versuchen Sie folgendes ...

SELECT id, 
     Name 
FROM Customer 
WHERE id NOT IN (SELECT customerid 
        FROM Tickets 
        WHERE ticketstatus <> 'closed' 
       ); 

Diese Anweisung listet die Customer ‚s id und name wo ihre id nicht angezeigt in einer Liste von customerid (aus der Tickets Tabelle), die einem anderen Status als closed entsprechen.

Keine Verbindung ist notwendig, es sei denn, Sie möchten die ticketstatus anzeigen, obwohl es immer closed sein wird. In diesem Fall versuchen Sie bitte die folgende ...

SELECT Customer.id AS id, 
     Name, 
     ticketstatus 
FROM Customer 
JOIN Tickets ON Customer.id = Tickets.customerid 
WHERE id NOT IN (SELECT customerid 
        FROM Tickets 
        WHERE ticketstatus <> 'closed' 
       ) 
GROUP BY Customer.id; 

Bitte beachten Sie das zusätzliche Feld in der Ausgabe und die JOIN aufgenommen werden, die ausgeführt wird. Da mehrere Instanzen der ausgewählten Felder möglich sind, weil der Kunde möglicherweise mehr als eine closedTicket hat, habe ich auch eine GROUP BY Customer.id-Klausel hinzugefügt, um die Ausgabe auf nur einen Datensatz für jede Customer zu reduzieren.

Wenn Sie irgendwelche Fragen oder Kommentare haben, dann zögern Sie nicht, einen Kommentar entsprechend zu posten.

+0

Dies wird Kunden erhalten, die überhaupt keine Tickets haben. –

+0

"Kein Joining notwendig" ist nicht ganz richtig, da eine NOT IN-Bedingung eine Form von Join ist (speziell ein ANTI-JOIN). Diese Form ist in der Tat weniger teuer als ein "Standard" beitreten. Dann: Die Bedingung NOT IN ist in Ordnung, wenn der Status niemals NULL sein kann. Wenn es NULL sein kann, muss mehr Sorgfalt angewandt werden. – mathguy

+0

mathguy, vielen Dank für den interessanten Kommentar zu ('NOT')' IN' und verschiedenen Arten von Joins. Ich habe es nie so gedacht. Außerdem stimme ich Ihrem Kommentar zu möglichen 'NULL' Problemen zu, obwohl ich in diesem Fall angenommen habe, dass' customerid' niemals 'NULL' Werte haben wird. – toonice

0

Try this: -

 Select distinct a.ID, a.Name as customername, b.ticketstatus 
      from 
      Customer a 
      inner join 
      Tickets b 
      on a.Id=b.CustomerId 
      where a.Id not in 
      (select CustomerId from 
      Tickets where ticketstatus <> 'closed' 
      ) 
      and b.ticketstatus='closed' 
      ; 

    OR 

    //With Same logic and different approach 

    Select distinct a.ID, a.Name as customername, b.ticketstatus 
     from 
     Customer a 

     inner join 

     (select CusotomerID,ticketstatus from Tickets 
     where ticketstatus='closed' 
     ) b 

     on a.Id=b.CustomerId 
     where a.Id not in 
     (select CustomerId from 
     Tickets where ticketstatus <> 'closed' 
     ) ; 
+0

Dies wird alle Kunden, die Tickets geschlossen haben, aber auch diejenigen mit geschlossenen Tickets, die offene Tickets haben, zurückgeben. –

+0

Es wurde behoben. Entschuldigen Sie das Missverständnis. –

+1

Dies wird eine falsche Ergebnismenge zurückgeben, wenn ein dritter "Ticketstatus" existiert oder jemals eingeführt wurde. Da die Frage speziell nach den Kunden fragt, deren "ticketstatus" -Werte auf "closed" gesetzt sind, können Sie Ihre Aussage robuster machen, indem Sie 'where ticketstatus = 'open'' in' where ticketstatus <>' closed 'ändern. '. – toonice

0

Was Sie wollen, ist für alle Benutzer zu finden, die mindestens ein Ticket haben und die haben keine Tickets, die nicht geschlossen werden:

SELECT c.id, c.name AS customername 
    FROM customers c 
WHERE EXISTS (SELECT 1 FROM tickets t 
       WHERE t.customerid = c.id) 
    AND NOT EXISTS (SELECT 1 FROM tickets t 
        WHERE t.customerid = c.id 
         AND t.ticketstatus != 'closed'); 

Hoffnung, das hilft.

-2

Sie suchen etwas wie folgt aus:

select distinct a.customername, b.ticketstatus from table1 a 
join table2 b on a.id = b.customerid 
where b.ticketstatus = 'closed' 
+0

Dies wird alle Kunden erhalten, die mindestens einen "geschlossenen" Status haben - nicht das, was das OP angefordert hat. – mathguy

+0

Dies wird alle Kunden zurückgeben, die mindestens ein "Ticket" mit einem "Ticketstatus" von "geschlossen" haben, einschließlich derjenigen, die ein anderes "Ticket" mit einem "Ticketstatus" von "offen" (oder einem anderen möglichen "Ticketstatus" -Wert haben)). – toonice

+0

Wird "b.ticketstatus" angezeigt? Wir wissen, dass es immer geschlossen wird. Außerdem empfehle ich auch, das Feld "a.id" (sofern nicht ausdrücklich anders angegeben) als eine Möglichkeit zur Unterscheidung zwischen doppelten Namen anzuzeigen. z.B. Wie gehst du mit zwei "John Smith" um? Schließlich sollte 'ein.Kundenname'' 'a.Name' 'laut der Tabellendefinition der Frage lesen. Sie können 'a.customername' in' A.Name AS-Kundenname' ändern, um den anderen Namen in der Ausgabe anzuzeigen. – toonice

1

Standard-Aggregat (sub) Abfrage auf der Ticket Tabelle, gefolgt von einem verbindet den Namen des Kunden zu erhalten:

with 
    customer (id, name, address) as (
     select 1, 'Manoj', 'Japan' from dual union all 
     select 2, 'Sunil', 'US' from dual 
    ), 
    tickets (id, customerid, ticketstatus) as (
     select 1, 1, 'closed' from dual union all 
     select 2, 1, 'closed' from dual union all 
     select 3, 2, 'closed' from dual union all 
     select 4, 1, 'open' from dual union all 
     select 5, 2, 'closed' from dual 
    ) 
-- END of test data (not part of the solution!) 
-- SQL query begins BELOW THIS LINE 
select s.id, c.name, 'closed' as ticketstatus 
from (
     select customerid as id 
     from  tickets 
     group by customerid 
     having min(ticketstatus) = 'closed' 
      and max(ticketstatus) = 'closed' 
     ) s 
     join customer c 
     on s.id = c.id 
; 

ID NAME TICKETSTATUS 
-- ----- ------------ 
2 Sunil closed 

Dies ist die ticketstatus übernimmt nicht NULL sein kann - sonst etwas muss darauf geachtet werden, da min() und max() ignorieren Nullen.

0

Ich würde Kunden und Tickets beitreten, um den benötigten Ergebnissatz zu definieren. Ich würde dann alle Kunden ausschließen, die Tickets haben, die nicht geschlossen sind. Ich habe Ticketstatus für den Fall verwendet, dass ein beliebiger Wert null sein könnte.

SELECT Distinct C.ID, C.Name as CustomerName, T.TicketStatus 
FROM Customer C 
INNER JOIN Tickets T 
on C.ID = T.customerID 
WHERE NOT EXISTS (SELECT 1 
        FROM TICKETS T2 
        WHERE coalesce(TicketStatus,'NULL') <> 'closed' 
        and T2.CustomerID = T.CustomerID) 
+0

Wird 'T.Ticketatus' angezeigt? Wir wissen, dass es immer "geschlossen" sein wird. – toonice

+0

Das ist eine Frage an den Urheber der Frage. Es ist in ihren erwarteten Ergebnissen; so ist es in meiner Antwort. Technisch gesehen konnte ich den Beitritt zu Tickets vermeiden und Hardcode 'geschlossen', um einen Leistungszuwachs zu bekommen ... aber * shrug * wenn sie sich ändern, um offen zu zeigen, dann müsste ich zwei statt eines Platzes wechseln. – xQbert

+0

Sie und 'India.Rocket' machen einen guten Punkt. Ich habe meine Antwort entsprechend angepasst. Vielen Dank. – toonice

Verwandte Themen