4

我有一个查询,当他们都知道这首歌并且状态已完成时,它会返回所选人员的歌曲名称列表。

当所有乐器都没有设置为“N/A”时,有没有办法只显示状态已完成的歌曲?

例如,假设表格内容如下。

    BandieName SongName 乐器状态
    Holly Wipeout Bells 完成
    Holly Centenial N/A Complete
    夏洛特消灭符号完成
    夏洛特 Centenial N/A 完成

如果我从列表中选择HollyCharlotte并运行查询,它将列出WipeoutCentenial,因为它们都将这些歌曲的状态设为已完成;但是,我不希望它显示Centenial,因为该歌曲的所有选定人员的乐器都是N/A

如果内容如下,并且我选择了其中的三首,我希望它显示所有三首歌曲,因为并非为该歌曲列出的所有乐器都是N/A

    BandieName SongName 乐器状态
    Holly Wipeout Bells 完成
    Holly Centenial N/A Complete
    夏洛特消灭符号完成
    夏洛特 Centenial N/A 完成
    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
4

4 回答 4

1

如果您的意思是找到所有指定名称的歌曲并且状态完整且其中至少一首(但不一定全部)具有非“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

显然,您在哪里建立了要检查的名称列表以及我替换值的相应名称计数,但这显示了原理。

于 2012-04-11T13:23:25.810 回答
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
于 2012-04-11T13:05:27.337 回答
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')
于 2012-04-11T13:11:50.467 回答
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,我建议您使用表参数,而不是在 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

我在你的一些一次性元素中添加了几个“使用”,但除此之外,我只是试图重用你的代码。

于 2012-04-11T13:22:44.623 回答