4

選択した人々の両方がその曲を知っていて、ステータスが完了しているときに、その曲名のリストを返すクエリがあります。

すべてのインストゥルメントが「N/A」に設定されていない場合、ステータスが完了している曲のみを表示する方法はありますか?

たとえば、テーブルの内容が次のようなものであるとします。

    BandieName SongName 楽器のステータス
    ホリー ワイプアウト ベル コンプリート
    ホリー センテニアル N/A コンプリート
    シャーロット ワイプアウト シンボルの完成
    シャーロット センテニアル N/A コンプリート

リストからHollyCharlotteを選択してクエリを実行すると、 WipeoutCentenialがリストされます。これらの曲はどちらもステータスが完了しているためです。ただし、その曲に選択されたすべての人が楽器をN/Aとして持っているため、 Centenialを表示したくありません。

コンテンツが以下のようなもので、そのうちの 3 つを選択した場合、その曲にリストされているすべての楽器がN/Aであるとは限らないため、3 つの曲すべてを表示したいと思います。

    BandieName SongName 楽器のステータス
    ホリー ワイプアウト ベル コンプリート
    ホリー センテニアル N/A コンプリート
    シャーロット ワイプアウト シンボルの完成
    シャーロット センテニアル N/A コンプリート
    ライアン ワイプアウト ドラム コンプリート
    ライアン センテニアル ドラム コンプリート

これまでの私のコードは次のとおりです。

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

指定されたすべての名前がその曲を持ち、ステータスが完了であり、そのうちの少なくとも 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

クエリは次のようになります。

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 に答える
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 に答える