3

GroupId、Member の 2 つのフィールドを持つテーブル ALPHA があります。

GroupId | Member;
A1----------A;
A1----------B; 
A1----------C;
A2----------A;
A2----------B;
A3----------A;
A3----------D;
A3----------E;

目的: A、B、C の入力が与えられた場合、テーブルをクエリして、この正確なメンバーのセットに GroupId が存在するかどうかを確認する必要があります。だから、これは私がやろうとしていることです:

  1. カウントが 3 であるすべての GroupId のテーブルを照会します (私の inpt は A、B、C であるため..私はその 3 を知っています)
  2. これにより、A1、A3が得られます。ここで、このセットに正確に一致するメンバー値を照会します。これにより、A1 が得られます。

ストアド プロシージャを作成する予定で、何とか目的を達成できます。しかし、私の質問は単一のクエリで実現できます...おそらく単一の自己結合です。

明確化: (A,B,C) のセットは A1 に固有です。また、(A、B、C、D) の入力を与える場合、クエリは A1 を返すべきではありません。

4

7 に答える 7

4
SELECT GroupID
  FROM ALPHA
 WHERE Member IN ('A', 'B', 'C')
 GROUP BY GroupID
HAVING COUNT(*) = 3

これは、IN 句でメンバーのリストを書き出し、HAVING 句でメンバー リストの (個別の) エントリ数を設定することに依存しています。このように SQL を生成できない場合は、さらに努力する必要があります。


初期のコメントで述べたように、これは、A、B、C の 3 つすべて (および場合によっては他のいくつか) がグループのメンバーであるグループが必要であるという解釈にも依存しています。必ずしも最良の方法ではありませんが、「グループに正確に 3 人、つまり A、B、C が含まれる場所」を取得する方法の 1 つは、次を使用することです。

SELECT GroupID
  FROM ALPHA A1
 WHERE Member IN ('A', 'B', 'C')
   AND 3 = (SELECT COUNT(*) FROM ALPHA A2 WHERE A2.GroupID = A1.GroupID)
 GROUP BY GroupID
HAVING COUNT(*) = 3

これにより、グループ内の合計人数が 3 人であり、メンバーが A、B、および C であることを明示的にチェックします (Alpha(GroupID, Member) に一意の制約があり、メンバーが 2 回リストされないようにすると仮定します)。同じグループに所属している)。

于 2009-09-04T18:16:02.980 に答える
2
SELECT DISTINCT aa.GroupId
FROM Alpha aa
JOIN Alpha ab ON (aa.GroupId = ab.GroupId)
JOIN Alpha ac ON (aa.GroupId = ac.GroupId)
LEFT OUTER JOIN Alpha ax ON (aa.GroupId = ax.GroupId AND ax.Member NOT IN ('A', 'B', 'C')
WHERE aa.Member = 'A' AND ab.Member = 'B' AND ac.Member = 'C'
 AND ax.GroupId IS NULL;

を含むソリューションもありGROUP BYますが、JOINソリューションの方がパフォーマンスが優れていることがよくあります。私は通常 MySQL で作業しており、MS SQL Server がクエリのグループ化に優れていることを理解しています。したがって、両方のソリューションを試して、使用している RDBMS のブランドに最適なものを確認してください。

于 2009-09-04T18:18:36.670 に答える
2

これまでの回答では、特定の GroupID に対して Member フィールドが一意であると想定しています。私が行った仕事では、これは当てはまりません。また、グループに探しているものと追加のものが含まれている場合は、そのグループを除外する必要があります。

SELECT
   [Alpha].GroupID
FROM
   [Alpha]
GROUP BY
   [Alpha].GroupID
HAVING
       SUM(CASE WHEN [alpha].Member IN ('A','B','C') THEN 1 ELSE 0 END) = 3
   AND MIN(CASE WHEN [alpha].Member IN ('A','B','C') THEN 1 ELSE 0 END) = 1


IN 句を、検索しているメンバーを保持するテーブルへの結合に置き換えることもできます...

SELECT
   [Alpha].GroupID
FROM
   [Alpha]
LEFT JOIN
   [Search]
       ON [Search].Member
GROUP BY
   [Alpha].GroupID
HAVING
       SUM(CASE WHEN [alpha].Member = [search].Member THEN 1 ELSE 0 END) = (SELECT COUNT(*) FROM [search])
   AND MIN(CASE WHEN [alpha].Member = [search].Member THEN 1 ELSE 0 END) = 1
于 2009-09-04T18:21:00.380 に答える
2

これを試して:

declare @YourTable table (GroupID char(2),Member char(1))

insert into @YourTable values ('A1','A')
insert into @YourTable values ('A1','B')
insert into @YourTable values ('A1','C')
insert into @YourTable values ('A2','A')
insert into @YourTable values ('A2','B')
insert into @YourTable values ('A3','A')
insert into @YourTable values ('A3','D')
insert into @YourTable values ('A3','E')
insert into @YourTable values ('A5','A')
insert into @YourTable values ('A5','B')
insert into @YourTable values ('A5','C')
insert into @YourTable values ('A5','D')
SELECT t1.GroupID
    FROM @YourTable t1
        LEFT OUTER JOIN @YourTable t2 ON t1.GroupID=t2.GroupID AND t2.Member NOT IN ('A', 'B', 'C') 
    WHERE t1.Member IN ('A', 'B', 'C') 
        AND t2.GroupID IS NULL
    GROUP BY t1.GroupID
    HAVING COUNT(*) = 3

出力:

GroupID
-------
A1

(1 row(s) affected)

完全な解決策は次のとおりです。

私の関数を使用する前に、「ヘルパー」テーブルを設定する必要があります。これを行う必要があるのは、データベースごとに 1 回だけです。

CREATE TABLE Numbers
(Number int  NOT NULL,
    CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
DECLARE @x int
SET @x=0
WHILE @x<8000
BEGIN
    SET @x=@x+1
    INSERT INTO Numbers VALUES (@x)
END

この関数を使用して文字列を分割します。これはループせず、非常に高速です。

CREATE FUNCTION [dbo].[FN_ListToTable]
(
     @SplitOn              char(1)              --REQUIRED, the character to split the @List string on
    ,@List                 varchar(8000)        --REQUIRED, the list to split apart
)
RETURNS
@ParsedList table
(
    ListValue varchar(500)
)
AS
BEGIN

/**
Takes the given @List string and splits it apart based on the given @SplitOn character.
A table is returned, one row per split item, with a column name "ListValue".
This function workes for fixed or variable lenght items.
Empty and null items will not be included in the results set.


Returns a table, one row per item in the list, with a column name "ListValue"

EXAMPLE:
----------
SELECT * FROM dbo.FN_ListToTable(',','1,12,123,1234,54321,6,A,*,|||,,,,B')

    returns:
        ListValue  
        -----------
        1
        12
        123
        1234
        54321
        6
        A
        *
        |||
        B

        (10 row(s) affected)

**/



----------------
--SINGLE QUERY-- --this will not return empty rows
----------------
INSERT INTO @ParsedList
        (ListValue)
    SELECT
        ListValue
        FROM (SELECT
                  LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue
                  FROM (
                           SELECT @SplitOn + @List + @SplitOn AS List2
                       ) AS dt
                      INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
                  WHERE SUBSTRING(List2, number, 1) = @SplitOn
             ) dt2
        WHERE ListValue IS NOT NULL AND ListValue!=''



RETURN

END --Function FN_ListToTable

この関数を次のように使用して、任意のリストを照会できます。

DECLARE @List varchar(100)
SET @List='A,B,C'
declare @YourTable table (GroupID char(2),Member char(1))

insert into @YourTable values ('A1','A')
insert into @YourTable values ('A1','B')
insert into @YourTable values ('A1','C')
insert into @YourTable values ('A2','A')
insert into @YourTable values ('A2','B')
insert into @YourTable values ('A3','A')
insert into @YourTable values ('A3','D')
insert into @YourTable values ('A3','E')
insert into @YourTable values ('A5','A')
insert into @YourTable values ('A5','B')
insert into @YourTable values ('A5','C')
insert into @YourTable values ('A5','D')

SELECT t1.GroupID
    FROM @YourTable t1
        LEFT OUTER JOIN @YourTable t2 ON t1.GroupID=t2.GroupID AND t2.Member NOT IN (SELECT ListValue FROM dbo.FN_ListToTable(',',@List))
    WHERE t1.Member IN (SELECT ListValue FROM dbo.FN_ListToTable(',',@List))
        AND t2.GroupID IS NULL
    GROUP BY t1.GroupID
    HAVING COUNT(*) = (SELECT COUNT(*) FROM dbo.FN_ListToTable(',',@List)) 

出力:

GroupID
-------
A1
于 2009-09-04T18:42:23.440 に答える
1

select * from ALPHA where Member in( COUNT(*) = 3 を持つメンバーごとに ALPHA グループからメンバーを選択)

于 2009-09-04T18:15:32.590 に答える
1

これを試してください:

SELECT GroupId
  FROM ALPHA
 GROUP BY GroupId
HAVING SUM(CASE WHEN Member='A' THEN 1.0
                WHEN Member='B' THEN 2.0
                WHEN Member='C' THEN 4.0
                ELSE 7.31415
          END) = 7.0
于 2009-09-04T18:16:39.500 に答える
0

私の提案は、その区切り文字列を一時テーブルに解析してから、このようなことを試すことです。

create table #temp(member varchar(10))

create table #groups
(
groupID varchar(2),
member char(1)
)

--#temp holds the members from your delimited string.
--#groups holds your relationships.



select distinct groupID
from #groups
where 
 (select count(*) from #groups i, #temp t
  where i.member = t.member and i.groupID = #groups.groupID) = 
(select count(*) from #temp)
于 2009-09-04T18:19:10.757 に答える