2012-04-11 50 views
3

我有一個返回所選歌曲的人的名單時,他們都知道這首歌,狀態爲完成查詢。選擇查詢,需要額外的where子句?

有沒有辦法,只顯示歌曲在狀態完成後,當所有的儀器都放不爲「N/A」?

例如,假設該表內容如下之一。

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

,如果我從列表中選擇冬青夏洛特,並運行該查詢,它會列出不經意的森田,因爲它們都具有這些歌曲作爲狀態的完整;不過,我不希望它顯示森田因爲所有這首歌所選擇的人有文書N/A

如果內容如下,並且我選擇了其中的三個,我希望它顯示所有三首歌曲,因爲並非所有列出的歌曲都是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 

我的代碼到目前爲止是以下一個。

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

因此,讓我澄清你的目標:你想要歌曲名稱連接到所有選定的BandieNames,都已完成狀態,並且至少有一個選擇了一些樂器(不是N/A)? – 2012-04-11 13:03:18

+0

就是這樣,此刻我可以獲得連接到所有選定的Bandienames的狀態完成的歌曲名稱,但希望這些歌曲名稱的狀態是完整的,並且至少有一個樂器不是N/A 謝謝 – Sophie 2012-04-11 13:09:09

+0

你使用的是什麼RDBMS? – GarethD 2012-04-11 13:48:53

回答

0

如果你的意思是找到的所有歌曲,所有指定名稱的歌曲和狀態完全和它們中的至少一個(但不一定是全部)具有非「N/A」值作爲工具,那麼你可以做幾種方法之一,例如:

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 

或者找到具有填充儀器匹配的品牌之一,並鏈接到所有匹配的歌曲:

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 

很顯然,你已經建立的名單要檢查的名稱以及我已替換的值的相應計數名稱但這顯示了原則。

+0

這是代表什麼?還specpectrument? 謝謝 – Sophie 2012-04-11 13:30:36

+0

他們只是表的別名 - 基本上(雖然s有點短:-))他們是關於以有意義的方式引用表。 S是歌曲列表,specInstrument找到了指定的樂器。這非常有用(特別是當在查詢中多次使用同一個表)明確表示查詢中的表所代表的內容時 – kaj 2012-04-11 13:36:14

+0

這很好用! THnaks – Sophie 2012-04-11 13:48:16

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

我認爲這完全不是什麼原始的海報問...你不是通過BandieName限制,你正在返回的歌曲可能具有除「完成」以外的狀態等。 – 2012-04-11 13:15:43

+0

狀態僅限於由子選擇。在閱讀OP的評論之後,我會編輯它以使其更像他們想要的。 – Maess 2012-04-11 13:22:41

+0

需要在所有Bandies上完成狀態,而不僅僅是選擇了一個(或多個)樂器的狀態。 – 2012-04-11 13:27:45

0

這可能不是最有效的搜索,但它應該工作。稍後我可以嘗試考慮更高效的解決方案。

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

我如何將這與我目前的代碼整合?名字來自列表框?它有'計數'和'有'條款? 謝謝 – Sophie 2012-04-11 13:14:36

+0

在循環所選波段的部分,您將創建兩個字符串,其中一個是last exists子句中使用的列表,另一個是重複的exists子句(我的示例中的前兩個)。然後,當你建立你的sql時,你編寫SELECT子句,FROM子句,包含重複的Exists子句,並在你最後建立的列表中添加最後一個EXISTS子句。 – 2012-04-11 13:18:20

0

您的查詢將是:

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' 
     ) 

如果您使用SQL Server 2008我reccomend使用表參數,而不是動態建立在VB.NET你的SQL,它消除了SQL的任何風險注射。你需要做的是這樣的情況如下:

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 

然後你可以使用VB代碼類似於此通過

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 

我添加了一對夫婦的「使用對你的一些一次性的參數元素,但除此之外,我只是試圖重用您的代碼。

+0

我不認爲你的第一個查詢滿足要求,因爲它不檢查所有的蝙蝠俠是完整的。它只檢查至少一個Bandie是否完整並且有一套樂器。 – 2012-04-12 06:30:15