2

私は、プロファイルを「一致させる」ようなアプリケーションを構築しています。たとえば、これが私のスキーマの縮小版です::

ユーザー IDFirstNameLastName
_
_

UserProfile Id
UserId
SomeOtherFields

UserProfileFieldsIdUserProfileId キー 値 _
_

UserProfileは、いくつかの標準情報(生年月日など)を保持するために存在します

UserProfileFieldsは基本的に、このような少しのように見える辞書を構築するためのキーとその値のリストです(ここでも、この質問の目的のために簡略化されています)

UserProfileID | Key       | Value       
123           | food      | Pizza
123           | food      | Indian
4453          | drink     | Coke
44850         | drink     | Orange Juice
88493         | food      | Pizza
448382        | food      | Chinese

したがって、上記から、プロファイル123が食品の88493と一致していることがわかります-どちらも食品|ピザを持っています

このテーブルを効率的にクエリして「一致」のリストを取得する方法はありますか

これを1日1回実行し、結果を別のテーブルに保存することを想定しています。

例えば:

一致する

MatchID | ProfileID
1       | 123
1       | 88493

私はの線に沿って何かを推測しています

SELECT * FROM UserProfileFields
GROUP BY Key

クエリの種類...しかし、これがどれほど効率的か、たとえば100万行かどうかはわかりませんか?

4

3 に答える 3

2

これはあなたのためにそれを処理する必要があります。

-- ============================================================================
-- BEGIN: SETUP TEST DATA
-- ============================================================================
CREATE TABLE UserProfileFields (
    UserProfileID   int
   ,[Key]           varchar(5)
   ,Value           varchar(12)
);


INSERT UserProfileFields (UserProfileID, [Key], Value)
SELECT A.*
  FROM (
        SELECT * FROM UserProfileFields WHERE 1=2
        UNION ALL SELECT 123,       'food',     'Pizza'
        UNION ALL SELECT 123,       'food',     'Indian'
        UNION ALL SELECT 4453,      'drink',    'Coke'
        UNION ALL SELECT 44850,     'drink',    'Orange Juice'
        UNION ALL SELECT 88493,     'food',     'Pizza'
        UNION ALL SELECT 448382,    'food',     'Chinese'
        UNION ALL SELECT 88493,     'drink',    'Coke'
        UNION ALL SELECT 88493,     'drink',    'Orange Juice'
       ) A;

--/*
-- Turn 8 records into 1,048,576
DECLARE @Count int; SELECT @Count = 0;
WHILE @Count < 17
  BEGIN
    INSERT UserProfileFields
    SELECT * FROM UserProfileFields

    SELECT @Count = (@Count + 1)
END
--*/
-- SELECT COUNT(*) FROM UserProfileFields WITH (NOLOCK)
-- ============================================================================
-- END: SETUP TEST DATA
-- ============================================================================




-- ============================================================================
-- BEGIN: Solution if Key, Value, and UserProfileID do NOT make up a unique key
-- ============================================================================
SET NOCOUNT ON
IF OBJECT_ID('tempdb..#DistinctValues', 'U') IS NOT NULL DROP TABLE #DistinctValues;
IF OBJECT_ID('tempdb..#Matches', 'U') IS NOT NULL DROP TABLE #Matches;

SELECT [Key], UserProfileID, Value 
  INTO #DistinctValues
  FROM UserProfileFields WITH (NOLOCK)
 GROUP BY [Key], UserProfileID, Value;

SELECT A.[Key], A.Value, A.UserProfileID
  INTO #Matches
  FROM #DistinctValues A
  JOIN #DistinctValues B
    ON A.[Key]           = B.[Key]
   AND A.Value           = B.Value
   AND A.UserProfileID  <> B.UserProfileID;

SELECT DENSE_RANK() OVER(ORDER BY A.[Key], A.Value) [MatchID]
      ,A.UserProfileID
      ,A.[Key]
      ,A.Value
  FROM #Matches A;
-- ============================================================================
-- END: Solution if Key, Value, and UserProfileID do NOT make up a unique key
-- ============================================================================




-- ============================================================================
-- BEGIN: Solution if Key, Value, and UserProfileID make up a unique key
-- ============================================================================
IF OBJECT_ID('tempdb..#Matches', 'U') IS NOT NULL DROP TABLE #Matches;

SELECT A.[Key], A.Value, A.UserProfileID
  INTO #Matches
  FROM UserProfileFields A WITH (NOLOCK)
  JOIN UserProfileFields B WITH (NOLOCK)
    ON A.[Key]           = B.[Key]
   AND A.Value           = B.Value
   AND A.UserProfileID  <> B.UserProfileID;

SELECT DENSE_RANK() OVER(ORDER BY A.[Key], A.Value) [MatchID]
      ,A.UserProfileID
      ,A.[Key]
      ,A.Value
  FROM #Matches A;
-- ============================================================================
-- END: Solution if Key, Value, and UserProfileID make up a unique key
-- ============================================================================
于 2013-03-15T06:03:15.927 に答える
1
WITH Matches
AS
(
    SELECT  a.UserProfileID,
            a.[Key],
            a.Value,
            DENSE_RANK() OVER(ORDER BY a.[Key]) MatchID
    FROM    UserProfileFields a
            INNER JOIN
            (
                SELECT  [Key], Value
                FROM    UserProfileFields 
                GROUP   BY [Key], Value
                HAVING  COUNT(DISTINCT UserProfileID) > 1
            ) b ON  a.[Key] = b.[Key] AND
                    a.Value = b.Value
)
SELECT  MatchID, UserProfileID
FROM    Matches
于 2013-03-15T01:10:37.827 に答える
1

EXISTS() 演算子とカバリング インデックスでオプションを使用します。これにより、過度のデータの並べ替えを回避できます。

CREATE INDEX ix_Key_Value_UserProfileFields ON dbo.UserProfileFields([Key], Value) INCLUDE(UserProfileID)

SELECT DENSE_RANK() OVER(ORDER BY t.[Key], t.Value) AS MatchID, t.UserProfileID
FROM dbo.UserProfileFields t
WHERE EXISTS (
              SELECT 1
              FROM dbo.UserProfileFields t2
              WHERE t.[Key] = t2.[Key]
                AND t.Value = t2.Value
              HAVING COUNT(*) > 1  
              )

ここに画像の説明を入力

SQLFiddle のデモ

于 2013-03-15T08:25:27.910 に答える