2010-11-28 3 views
2

次のクエリは、グラフ内の2つのノードの共通隣人カウント:それは例えばので、user1とuser2のことで呼ばれている一般的な隣人の数を返し、次のグラフ alt textUNIONの代わりにJOINを使用して "A OR B"の近隣を数える方法?

について

DECLARE @monthly_connections_test TABLE (
    calling_party VARCHAR(50) 
    , called_party VARCHAR(50)) 

INSERT INTO @monthly_connections_test 
      SELECT 'z1', 'z2' 
UNION ALL SELECT 'z1', 'z3' 
UNION ALL SELECT 'z1', 'z4' 
UNION ALL SELECT 'z1', 'z5' 
UNION ALL SELECT 'z1', 'z6' 
UNION ALL SELECT 'z2', 'z1' 
UNION ALL SELECT 'z2', 'z4' 
UNION ALL SELECT 'z2', 'z5' 
UNION ALL SELECT 'z2', 'z7' 
UNION ALL SELECT 'z3', 'z1' 
UNION ALL SELECT 'z4', 'z7' 
UNION ALL SELECT 'z5', 'z1' 
UNION ALL SELECT 'z5', 'z2' 
UNION ALL SELECT 'z7', 'z4' 
UNION ALL SELECT 'z7', 'z2' 

SELECT  monthly_connections_test.calling_party AS user1, monthly_connections_test_1.calling_party AS user2, COUNT(*) AS calling_calling, 0 AS calling_called, 
         0 AS called_calling, 0 AS called_called, 0 AS both_directions 
FROM   @monthly_connections_test AS monthly_connections_test INNER JOIN 
         @monthly_connections_test AS monthly_connections_test_1 ON 
         monthly_connections_test.called_party = monthly_connections_test_1.called_party AND 
         monthly_connections_test.calling_party < monthly_connections_test_1.calling_party 
GROUP BY monthly_connections_test.calling_party, monthly_connections_test_1.calling_party 

をz1とz2によって呼び出された隣人の数は、z4とz5の両方の呼び出しとして2を返します。

もう1つのことは、user1またはuser2のどちらかによって呼び出される2つのノード(ユーザー)のすべての近隣ノードの数です。たとえば、クエリ(z1、z2) (z1、z2)が観測された対であり、(z3、z4、z5、z6)の要素の数がz1、z2、z3、 、z4、z5、z6)U(z4、z5、z7)は5である。

誰も上記のロジックの結合クエリを変更/作成する方法を知っていますか?

ありがとうございました!

+0

はでスクリプトを持っている方が良いです:1)テーブル及び2)挿入を作成します。データを使って遊ぶのが簡単で、最適な方法をより迅速に見つけることができます。ありがとうございました – Genius

+0

提案ありがとう! –

+0

テーブル名を全長で繰り返すのではなく、短縮形のテーブルエイリアスを使うことを強くお勧めします。 '@monthly_connections_test AS mct'。文脈では、私は 'mct1'と' mct2'、さらには 'm1'と' m2'を使います。これは、SQLをより読みやすくします(また、水平スクロールバーを回避するのに役立ちますが、読みやすさの向上よりもそれほど重要ではありません)。 –

答えて

2

@マーティンの答えは正しいです。彼は天才です。

Go Martin!私が与えた双方向の溶液に対して実行する場合

CORRECTION

彼の答えは1回の小さな変更で動作します。それ以外の場合、結果は正しくありません。

だからあなたの答え彼の彼と私:)

完全なソリューション:そのような質問について

DECLARE @T1 TABLE (calling_party VARCHAR(50), called_party VARCHAR(50)) 

INSERT INTO @T1 
SELECT * 
FROM dbo.monthly_connections_test 

INSERT INTO @T1 
SELECT * 
FROM (
     SELECT called_party AS calling_party, calling_party AS called_party 
     FROM dbo.monthly_connections_test AS T2 
     WHERE T2.called_party < T2.calling_party 
     ) T2 
WHERE NOT EXISTS (
     SELECT * 
     FROM monthly_connections_test 
     WHERE calling_party = T2.calling_party and called_party = T2.called_party 
) 

select u1, u2, count(called_party) called_parties 
from (
select distinct u1, u2, called_party from 
(
     select a1.calling_party u1, a2.calling_party u2 from 
     (select calling_party from @T1 group by calling_party) a1, 
     (select calling_party from @T1 group by calling_party) a2 
) pairs, 
@T1 AS T 
where 
(u1 <> u2) and 
((u1 = t.calling_party and u2 <> t.called_party) or 
(u2 = t.calling_party and u1 <> t.called_party)) 
) res 
group by u1, u2 
order by u1, u2 
+0

ありがとうございました:)。私がこれを正しく読んでいるならば、あなたの変換コードは逆の関係を追加します(例えば、z6-> z1-> z6-> z1)。本当にあなたが望むものに依存します:あなたがuser1またはuser2と電話をしたユーザーを望む場合は、* u1またはu2で*アクティブに呼び出されたユーザーのみが必要な場合は修正が必要です。 – Martin

+0

正しい。私のコードは着信コールを追加し、効果的にテーブルを一方向にします。私はあなたのコードがなぜ必要なのかまだ分かりません。なぜなら、あなたは<演算子がないので、なぜ制限されているのかわかりません。 – IamIC

+0

結果を比較すると、変換がなければ、最初の発信者*にも電話していないユーザーは見落とされているように見えます(あなたのコメントでは反対です)。例えば。z6は変換によって追加され、グラフごとに呼び出されますが呼び出されません。 – IamIC

0

興味深いことに、希望の結果(z2、z3、z4、z5、z6)U(z1、z4、z5、z7)を7とすると、

COMPUTE操作で必要なカウントが得られますか?

+0

z1とz2のネイバーを探しているので、z1とz2を除外する必要があります。 –

+0

これは手動で再構築する複雑なクエリです。コミュニティメンバーがこのケースで簡単に作業できるように、CREATE TABLEスクリプトに必要なINSERTを含めることをお勧めします。 – IamIC

+0

+1本当のチャレンジ! – IamIC

0

これはひどく壊れやすいナットです。

最初の問題は、データがテーブル内で双方向であることです。これを解決するための第一歩は、データを一方向にすることです。 1関係:

DECLARE @T1 TABLE (calling_party VARCHAR(50), called_party VARCHAR(50)) 
DECLARE @T2 TABLE (calling_party VARCHAR(50), called_party VARCHAR(50)) 

INSERT INTO @T1 
SELECT * 
FROM dbo.monthly_connections_test 

INSERT INTO @T1 
SELECT * 
FROM (
     SELECT called_party AS calling_party, calling_party AS called_party 
     FROM dbo.monthly_connections_test AS T2 
     WHERE T2.called_party < T2.calling_party 
     ) T2 
WHERE NOT EXISTS (
     SELECT * 
     FROM monthly_connections_test 
     WHERE calling_party = T2.calling_party and called_party = T2.called_party 
) 

INSERT INTO @T2 
SELECT DISTINCT TOP (100) PERCENT calling_party, called_party 
FROM @T1 
WHERE calling_party < called_party 
UNION 
SELECT DISTINCT TOP (100) PERCENT called_party AS calling_party, calling_party AS called_party 
FROM @T1 
WHERE calling_party > called_party 

上記完全は異なる1にデータをアンラップすることにより、任意の双方向の問題を解決します。結果は、元のデータごとにすべての関係を表す9レコードだけです。

私は(これらの時間の後、これも私の問題です)結果を照会してネイバーを必要に応じて得ることができるはずです。これは次のハードルです...

0

Niko、私はこの質問のテーブルの例に欠けているデータポイントがあると思います。私は私のテストのために以下を追加しました。

UNION ALL SELECT 'z1', 'z6' 

私が質問に答えるために、2つの単純なクエリを持っている:私はカウントしたい

「user1とuser2のことで呼ばれている一般的な隣人の数」

は、「すべての数でありますいずれかによって呼ばれる2つのノード(ユーザ)の隣人USER1またはuser2" の

私はここにSQL Serverを持たない
declare @Party1 varchar(10) 
declare @Party2 varchar(10) 
set @Party1 = 'z1' 
set @Party2 = 'z2' 
select count(distinct called_party) AS 'Total calls 2 neighbors' 
from @monthly_connections_test 
WHERE calling_party in (@Party1, @Party2) 
AND called_party not in (@Party1 , @Party2) 

;With cteAllCalls(x) as 
(
Select called_party from @monthly_connections_test 
where called_party != @Party1 and calling_party = @Party2 
) 

select Count(X) AS 'Total common calls' from cteAllCalls 
inner join @monthly_connections_test on x = called_party 
and called_party != @Party2 and calling_party = @Party1 
+0

私はこの「欠けているデータポイント」に解決策を与えます。しかし、私は解決策が2つのパーティーを設定することを含むとは思わない。これはグラフなので、結果セットは自動的にすべての入力データのクロス結合に置換されます。 – IamIC

+0

RC_Clelandの提案をありがとうございます。しかし、IanCが言及した問題は、クエリがどの組み合わせをカウントするかを手動で宣言せずに、すべての順列を自動的に検索しなければならないということです。 –

1

が、これべき作品:

select u1, u2, count(called_party) called_parties 
from (
select distinct u1, u2, called_party from 
(
    select a1.calling_party u1, a2.calling_party u2 from 
     (select calling_party from @monthly_connections_test group by calling_party) a1, 
     (select calling_party from @monthly_connections_test group by calling_party) a2 
) pairs, 
@monthly_connections_test t 
where 
(u1 = t.calling_party and u2 <> t.called_party) or 
(u2 = t.calling_party and u1 <> t.called_party) 
) res 
group by u1, u2; 

pairsサブクエリ単純なユーザーのすべての可能なペアを作成するには、おそらくどこかにユーザリストを持っています。

+0

このソリューションは賢明ですが、スケーラビリティはありますか?この小さなデータセットでは、294レコードを作成して処理します。これは元のデータで指数関数的に拡張されます。 – IamIC

+0

そうだと思います。ほとんどのDBは内側のクエリを決して拡張しません(つまり、テーブルが見つかると行数がカウントされ、巨大な一時テーブルは作成されません)。 monthly_connections_test(ペアクエリを無視する)のフルスキャンは1回だけですので、非常に安価です。 – Martin

+0

私はそれをテストしたいと思っています...それは巧妙な解決策です。私が得ることができない唯一の理由は、100%作業するために私の変換コードが必要な理由です。どのようにそれを把握しましたか?それはかなり「箱の外」です。 – IamIC

関連する問題