2012-04-11 10 views
3

Ich habe eine Abfrage, die eine Liste der Songnamen für die ausgewählten Personen zurückgibt, wenn beide wissen, dass der Song und der Status abgeschlossen ist.Abfrage auswählen, zusätzliche where-Klausel benötigen?

Gibt es eine Möglichkeit, nur die Songs anzuzeigen, bei denen der Status komplett ist, wenn alle Instrumente nicht als 'N/A' eingestellt sind?

Angenommen, der Tabelleninhalt ist der folgende.

 
    BandieName SongName Instrument Status 
    Holly  Wipeout  Bells  Complete 
    Holly  Centenial N/A   Complete 
    Charlotte Wipeout  Symbols  Complete 
    Charlotte Centenial N/A   Complete 

wenn ich Holly und Charlotte aus der Liste auswählen, und die Abfrage ausführen, wird es Liste Wipeout und Centenial, da sie beide haben diese Lieder als Status abgeschlossen; aber ich möchte nicht, dass es Centenial zeigt, weil alle ausgewählten Leute für dieses Lied Instrument wie N/A haben.

Wenn der Inhalt wie folgt war, und ich wählte die drei von ihnen, würde ich wollen, dass es alle drei Songs zeigt, da nicht alle Instrumente für dieses Lied aufgeführt sind N/A.

 
    BandieName SongName Instrument Status 
    Holly  Wipeout  Bells  Complete 
    Holly  Centenial N/A   Complete 
    Charlotte Wipeout  Symbols  Complete 
    Charlotte Centenial N/A   Complete 
    Ryan  Wipeout  Drum  Complete 
    Ryan  Centenial Drum  Complete 

Mein Code ist bisher der folgende.

Protected Sub btnGetPlaylist_Click(sender As Object, e As System.EventArgs) Handles btnGetPlaylist.Click 

    Dim conn As SqlConnection = Nothing 
    Try 
     Dim connString As String = "Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\BandDatabase.mdf;Integrated Security=True;User Instance=True" 
     conn = New SqlConnection(connString) 

     Dim sqlBandies As String 

     Dim item As ListItem 
     For Each item In ListBoxBandies.Items 
      If item.Selected Then 

       Dim selectedBandies As String = item.Text 
       sqlBandies &= "'" & item.Text & "', " 

      End If 
     Next 

     Dim amountSelected As String = ListBoxBandies.Items.Count.ToString 


     Dim query As String = "select SongName from Learning where BandieName in (" + sqlBandies + " '') AND Status = 'Complete' group by SongName having count(distinct BandieName) = " + ListBoxBandies.GetSelectedIndices.Length.ToString 

     Dim cmd As SqlCommand = New SqlCommand(query, conn) 

     conn.Open() 
     Dim dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) 
     Dim dt As DataTable = New DataTable() 
     dt.Load(dr) 
     GridViewPlaylist.DataSource = dt 
     GridViewPlaylist.DataBind() 


    Finally 
     conn.Close() 
    End Try 

End Sub 
+0

Also lassen Sie mich Ihr Ziel klarstellen: Sie wollen Songnamen, die mit ALLEN ausgewählten BandieNames verbunden sind, alle haben den Status abgeschlossen und AT MINDS ONE hat ein Instrument (nicht N/A) ausgewählt? –

+0

Ja, das ist es, im Moment kann ich die Songnamen mit allen ausgewählten Bandenamen verbinden, wo der Status komplett ist, aber die Songnamen wollen, wo der Status komplett ist und mindestens eins der Instrumente ist nicht N/A Danke – Sophie

+0

Welche RDBMS verwenden Sie? – GarethD

Antwort

0

Wenn Sie meinen, alle Songs zu finden, bei denen alle angegebenen Namen den Song enthalten und der Status komplett ist und mindestens einer von ihnen (aber nicht unbedingt alle) einen nicht "N/A" Wert als Instrument hat, dann können Sie das tun einer von mehreren Ansätzen, zB:

select s.SongName 
from Learning s 
    left outer join Learning specInstrument on specInstrument.SongName = s.SongName and specInstrument.BandieName = s.BandieName and specInstrument.Instrument <> 'N/A' 
where s.BandieName in ('Holly', 'Charlotte') 
    and s.Status = 'Complete' 
having count (distinct s.BandieName) = 2 
and count(specInstrument.SongName) > 0 

oder alle passenden Songs finden, die für einen der passenden Namen und Link zu, dass ein besiedeltes Instrument haben:

select s.SongName 
from Learning s 
inner join (select SongName from Learning where status = 'Complete' and BandieName in ('Holly', 'Charlotte') and instrument <> 'N/A') hasInstr on hasInstr.SongName = s.SongName 
where s.BandieName in ('Holly','Charlotte') 
and status = 'Complete' 
group by s.SongName 
having count(distinct s.BandieName) = 2 

Offensichtlich wo Sie die Liste erstellt haben zu überprüfende Namen und die entsprechende Anzahl von Namen, die ich ersetzt habe Es zeigt aber das Prinzip.

+0

Was bedeutet das? auch specInstrument? Danke – Sophie

+0

Sie sind nur Aliase für die Tabelle - im Grunde (obwohl s ist ein bisschen kurz :-)) sie beziehen sich auf die Tabelle in einer sinnvollen Weise. Da S die Songliste ist, wurde ein spezifiziertes Instrument gefunden. Es ist nur nützlich (vor allem, wenn Sie dieselbe Tabelle mehrmals in einer Abfrage verwenden), explizit anzugeben, was eine Tabelle in einer Abfrage darstellt. – kaj

+0

Das funktioniert großartig! THnaks – Sophie

0
SELECT 
    BandName 
    , SongName 
    , Instrument 
    , Status 
FROM Learning as l1 
INNER JOIN (
       Select 
        BandName 
        , SongName 
       FROM Learning 
       WHERE Instrument <> 'N/A' AND Status = 'Complete' 
      ) AS l2 
    ON l1.BandName = l2.BandName AND l1.SongName = l2.SongName 
+0

Ich glaube nicht, dass das alles ist, was das ursprüngliche Poster verlangt ... Sie beschränken nicht durch BandieName, Sie geben Songs zurück, die möglicherweise einen anderen Status als "Complete" haben, usw. –

+0

Der Status ist auf die Vollständigkeit beschränkt Unterauswahl. Nach dem Lesen der OPs Kommentare, werde ich bearbeiten, um es mehr wie das, was sie wollen, zu machen. – Maess

+0

Der Status muss für alle Bandies vollständig sein, nicht nur für den einen (oder viele), für den ein Instrument ausgewählt wurde. –

0

Dies kann nicht die effizienteste Suche sein, aber es sollte funktionieren. Ich kann versuchen, etwas später eine effizientere Lösung zu finden.

SELECT DISTINCT SongName 
FROM Learning l1 
WHERE 
    EXISTS (
     SELECT * 
     FROM Learning l2 
     WHERE l1.BandieName = '<First selected BandieName>' 
      AND l1.SongName = l2.SongName 
      AND l2.Status = 'Complete') 
    AND EXISTS (
     SELECT * 
     FROM Learning l3 
     WHERE l1.BandieName = '<Second selected BandieName>' 
      AND l1.SongName = l3.SongName 
      AND l3.Status = 'Complete') 
    -- Repeat these for however many people are selected. 
    AND EXISTS (
     SELECT * 
     FROM Learning lInstrument 
     WHERE NOT lInstrument = 'N/A' 
      AND l1.SongName = lInstrument.SongName 
      AND BandieName IN (<BandieName list>) 
      AND lInstrument.Status = 'Complete') 
+0

Wie würde ich das mit meinem aktuellen Code integrieren? Woher kommen die Namen aus dem Listenfeld? und es hat die "zählen" und "haben" -Klausel in? Dank – Sophie

+0

In dem Abschnitt, wo Sie die ausgewählten Bänder durchlaufen, erstellen Sie zwei Zeichenfolgen, wobei eine die Liste in der letzten exists-Klausel verwendet und die zweite die repeated exists-Klauseln (die ersten beiden in meinem Beispiel). Wenn Sie dann Ihren SQL-Code erstellen, schreiben Sie die SELECT-Klausel, die FROM-Klausel, enthalten die wiederholten Exists-Klauseln und fügen die letzte EXISTS-Klausel mit der von Ihnen erstellten Liste hinzu. –

0

Ihre Abfrage wäre:

WITH LearningCTE AS 
( SELECT * 
    FROM Learning 
    WHERE BandieName IN ('Holly', 'Charlotte', 'Ryan') 
    AND  Status = 'Complete' 
) 
SELECT * 
FROM LearningCTE a 
WHERE EXISTS 
     ( SELECT 1 
      FROM LearningCTE b 
      WHERE a.SongName = b.SongName 
      AND  Instrument != 'N/A' 
     ) 

Wenn Ihr SQL Server 2008 verwenden würde ich eher einen Tabellenparameter reccomend mit als dynamisch den Aufbau Ihrer SQL in VB.NET, entfernt es das Risiko von SQL Injektion. Sie müssen so etwas wie die folgenden tun:

CREATE TYPE NameList AS TABLE (Name VARCHAR(50)) 
GO 
CREATE PROCEDURE dbo.GetPlayList (@Names NameList) 
AS 
BEGIN 
    WITH LearningCTE AS 
    ( SELECT l.* 
     FROM Learning l 
       INNER JOIN @Names 
        ON BandieName = Name 
     WHERE Status = 'Complete' 
    ) 
    SELECT * 
    FROM LearningCTE a 
    WHERE EXISTS 
      ( SELECT 1 
       FROM LearningCTE b 
       WHERE a.SongName = b.SongName 
       AND  Instrument != 'N/A' 
      ) 
END 

Dann sind Sie VB-Code verwandt diese verwenden können, um die Parameter übergeben

Protected Sub btnGetPlaylist_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnGetPlaylist.Click 
     Dim conn As SqlConnection = Nothing 
     Try 
      Dim connString As String = "Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\BandDatabase.mdf;Integrated Security=True;User Instance=True" 
      conn = New SqlConnection(connString) 

      Dim NameTable As New DataTable() 
      NameTable.Columns.Add("Name", GetType(String)) 

      For Each item As ListItem In ListBoxBandies.Items 
       If item.Selected Then 
        Dim newRow As DataRow = NameTable.NewRow() 
        newRow(0) = item.Text 
        NameTable.Rows.Add(newRow) 
       End If 
      Next 

      Using cmd As SqlCommand = New SqlCommand("dbo.GetPlayList", conn) 
       cmd.Parameters.Add(New SqlParameter("@Names", NameTable)) 
       cmd.CommandType = CommandType.StoredProcedure 
       conn.Open() 
       Using dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) 
        Dim dt As DataTable = New DataTable() 
        dt.Load(dr) 
        GridViewPlaylist.DataSource = dt 
        GridViewPlaylist.DataBind() 
       End Using 
      End Using 
     Finally 
      conn.Close() 
     End Try 

    End Sub 

ich ein paar ‚mit der, um einige Ihrer Wegwerf hinzugefügt haben Elemente, aber abgesehen davon habe ich gerade versucht, den Code wiederzuverwenden.

+0

Ich denke nicht, dass Ihre erste Abfrage die Anforderungen erfüllt, da nicht überprüft wird, ob alle Bandies vollständig sind. Es prüft nur, ob mindestens ein Bandie komplett ist und ein Instrumentenset hat. –