2012-04-11 49 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