选择查询,需要额外的where子句吗?

时间:2012-04-11 12:53:51

标签: sql

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

当所有乐器都没有作为'N / A'时,有没有办法只显示状态完成的歌曲?

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

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

如果我从列表中选择 Holly Charlotte 并运行查询,它将列出 Wipeout Centenial ,因为他们都将这些歌曲作为状态完成;但是,我不希望它显示 Centenial ,因为该歌曲的所有选定人员都将乐器设为 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

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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')

答案 2 :(得分: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

我已经为你的一些一次性元素添加了一些'使用',但除此之外,我只是尝试重用你的代码。