2016-02-10 12 views
6

に沿ってデータを移動する...SQL私もこれで開始する見当がつかないが、ここで私は何をする必要があるかの列

我々は内のアドレスと電話番号を持つテーブルを持っている。しかし、私は削減する必要があります6〜3の電話番号の列。右から左に番号を移動して、空のセルに移動します。

以下の例 -

表は What the table looks like

どのように見えるか、私はそれが What i want it to look like

+0

これはselectで必要ですか、またはデータを更新したいですか? – Betlista

+2

あなたのデータベースは?これまでに何を試しましたか? http://stackoverflow.com/help/how-to-ask –

+0

可能であればSELECTで – giddygoose

答えて

3

PIVOTおよびUNPIVOTは仕事をすることができます。アイデア:

  1. UNPIVOT空の行を一掃し、新しい列が戻っ列にきれいにデータを取得するために
  2. PIVOTがどうなるかを計算する行
  3. にデータを取得します。

ここでは、1つのステートメントで複数のCTEを使用する方法の1つです。私はID列があると仮定しましたと私はテーブル名を作ってきました注意:

;WITH Unpivoted AS 
(
    -- our data into rows 
    SELECT ID, TelField, Tel 
    FROM Telephone 
    UNPIVOT 
    (
     Tel FOR TelField IN (TEL01,TEL02,TEL03,TEL04,TEL05,TEL06) 
    ) as up 
), 
Cleaned AS 
(
    -- cleaning the empty rows 
    SELECT 
     'TEL0' + CAST(ROW_NUMBER() OVER (PARTITION BY ID ORDER BY TelField) AS VARCHAR) [NewTelField], 
     ID, 
     TelField, 
     Tel 
    FROM Unpivoted 
    WHERE NULLIF(NULLIF(Tel, ''), 'n/a') IS NOT NULL 
), 
Pivoted AS 
(
    -- pivoting back into columns 
    SELECT ID, TEL01, TEL02, TEL03 
    FROM 
    (
     SELECT ID, NewTelField, Tel 
     FROM Cleaned 
    ) t 
    PIVOT 
    (
     -- simply add ", TEL04, TEL05, TEL06" if you want to still see the 
     -- other columns (or if you will have more than 3 final telephone numbers) 
     MIN(Tel) FOR NewTelField IN (TEL01, TEL02, TEL03) 
    ) pvt 
) 
SELECT * FROM Pivoted 
ORDER BY ID 

一度に正しい場所に電話番号をシフトすること。 PivotedSELECT * FROM Pivotedに他のCTEのいずれかに変更することもできます(UnpivotedCleaned)。部分的な結果がどのように表示されるかを確認することもできます。最終結果:

Results

+0

愚かな音がないどこから列と番号を取得しますか?または単に例として使用していますか? – giddygoose

+0

'Number'はピリオドされていないTEL01-06フィールドの名前です。 'Tel'はこれらのフィールドの値です。スクリプトを変更して、代わりに 'TelField'と言って少し明確にしました。 TechNetライブラリには、 'PIVOT'と' UNPIVOT'クエリを構成する方法の詳細があります。 https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx – Balah

+0

おかげでバラ、あなたの説明は上にスポットです!そして、ソリューションのおかげで、それは治療を働く。 – giddygoose

0

ようになりたいあなたはこれを行うことができ、いくつかの異なる方法がありますが、最適な選択は、使用しているデータベースエンジン、および/または他のどのツールが利用可能かによって異なります。

最も厄介な方法は、64の可能な組み合わせ(6つのフィールドがすべて空白で6つのフィールドがすべて入力されている場所を含む)でデータをフェッチする64の異なるSQL文を書くことです。ただし、練習。

問題は、問題空間を単純なものに減らすための単純で反復可能なアルゴリズムを見つけることです。

これを実行する1つの方法は、可能な場合はシフトを1つのスペースの左側に実行する6つのステートメントを書くことです。

フィールド1にフィールド2から

update table set field1 = field2, field2 = null from table 
where field2 is not null and field1 is null 

移動の内容、およびフィールド1は空白で、フィールド2は、第2の文の空白

ない場合のみとします。

update table set field2 = field3, field3 = null from table 
where field3 is not null and field2 is null 

は同じこと - などをon:

合計で5つのステートメントがあります。すべてをバッチとして実行すると、 ftレコードはバッチごとに最低1つずつ格納されます。左に空きスペースがあり、右にすべてのレコードがギャップなしで隣接する場合、バッチごとに移動します。ギャップは右側に移動する傾向がありますので、バッチを最低6回実行すると、必要なものに合ったデータセットを見つけることができます。

あなたが必要とする実際のSQLは、RDBMS言語がNULLや空文字列などをどのように扱うかに依存しますが、5つの文しか必要ではなく、比較的少数。

これよりももっと洗練された方法がありますが、これはかなり簡単で、バッチを実行するたびに、あなたはどこにいても一歩近づくことができます。ダウンサイドでは、それはちょっとclunkyです。これを定期的に実行する必要がある場合は、もう少し洗練されたものを見つけ出すように誘惑されるかもしれません。

datasizeに応じて、各組み合わせ/ヌルカウントのレコード数を分類/カウントするものを実行する価値があります。そうすれば、実行しなければならないランの数を減らすことが可能になる可能性があります。チャンスは、4つまたは5つの異なるパターンであり、完全な64ではありません。

0

サンプルデータ:

IF OBJECT_ID('tempdb..#temp') IS NOT NULL 
DROP TABLE #temp; 

SELECT * 
INTO #temp 
FROM 
(SELECT NULL TEL1, NULL TEL2, 1 TEL3, NULL TEL4, 2 TEL5,3 TEL6 
UNION ALL 
SELECT 4 TEL1, NULL TEL2,5 TEL3, NULL TEL4, NULL TEL5,NULL TEL6 
UNION ALL 
SELECT 6 TEL1, NULL TEL2,7 TEL3, NULL TEL4, NULL TEL5,NULL TEL6 
UNION ALL 
SELECT NULL TEL1, 8 TEL2,9 TEL3, 10 TEL4, NULL TEL5,NULL TEL6 
UNION ALL 
SELECT NULL TEL1, NULL TEL2,11 TEL3, NULL TEL4, 12 TEL5,NULL TEL6 
UNION ALL 
SELECT NULL TEL1, 13 TEL2,14 TEL3, NULL TEL4, 15 TEL5,NULL TEL6 
UNION ALL 
SELECT 16 TEL1, NULL TEL2,17 TEL3, NULL TEL4, NULL TEL5,18 TEL6 
UNION ALL 
SELECT NULL TEL1, 19 TEL2,20 TEL3, NULL TEL4, NULL TEL5,21 TEL6 
UNION ALL 
SELECT 22 TEL1, NULL TEL2,23 TEL3, NULL TEL4, 24 TEL5,NULL TEL6 
UNION ALL 
SELECT NULL TEL1, 25 TEL2,26 TEL3, NULL TEL4, NULL TEL5,27 TEL6) AS A 



SELECT * FROM #temp 

enter image description here

SOLUTION:

;WITH CTE AS (
SELECT ID, 'TEL' + CAST(ROW_NUMBER() OVER (PARTITION BY ID ORDER BY PHONE) AS VARCHAR) AS PHONE,VALUE FROM 
(SELECT NEWID() AS ID,* FROM #temp) AS P UNPIVOT 
(Value FOR Phone IN (TEL1 ,TEL2, TEL3, TEL4, TEL5, TEL6)) AS unpvt) 

SELECT [TEL1],[TEL2],[TEL3] FROM 
(SELECT * FROM CTE) P PIVOT (MAX(VALUE) FOR Phone IN 
([TEL1],[TEL2],[TEL3]) 
) AS pvt 

結果: enter image description here

+1

あなたのクエリと結果は正しいかもしれませんが、各列の値に1を使用すると、OPが望むように結果が各行で順序付けされていることを確かめるのが難しくなります。 –

+0

コメントのために@ PaulWilliamsさんに感謝します。私はサンプルデータの値を少し変更しやすくしました。 –

関連する問題