2016-06-08 23 views
1

Ich möchte eine dynamische Auswahl erstellen, die jeden eindeutigen Wert für jede Spalte in einer breiten Tabelle zurückgibt. I.e.Jeder eindeutige Wert für jede Spalte

select distinct @mycolumn 
from @mytable 

für jede Spalte und die Ergebnisse zu einer einzigen Tabelle zusammengefasst.

Edit1:

Beispiel: Example

EDIT2: Die Reihenfolge der zurückgegebenen Daten wird keine Rolle, und die Quelltabelle alle Arten von Datentypen haben.

Jeder Ratschlag geschätzt, danke!

+2

Unterscheiden sich die Datentypen Ihrer Spalten nicht? – Heinzi

+3

Beispieldaten und gewünschte Ergebnisse anzeigen. –

+2

Ich kann mir kein Szenario vorstellen, wo das nützlich wäre. Wie würdest du sie trotzdem kombinieren? Ich schätze mal, jede Spalte hat eine andere Anzahl an eindeutigen Werten .... –

Antwort

2

Der einzige Weg, an den ich denken kann, ist sehr umständlich und wahrscheinlich extrem langsam: Verwenden einer Tally-Tabelle (Ich habe eine rekursive Cte ​​für diese Antwort erzeugt, aber das ist auch kein sehr guter Weg tun Sie das ...) und mehrere abgeleitete Tabellen, die mit dieser Tabelle verknüpft sind, konnte ich etwas entwickeln, das die gewünschte Ausgabe erzeugt.
Allerdings, wie ich oben geschrieben habe - es ist sehr umständlich und wahrscheinlich extrem langsam (Ich habe nur auf eine Tabelle mit 5 Spalten und 6 Zeilen getestet, so habe ich keine Ahnung über die Ausführungsgeschwindigkeit).

DECLARE @Count int 
select @Count = COUNT(1) 
FROM YourTable 

;with tally as (
    select 1 as n 
    union all 
    select n + 1 
    from tally 
    where n < @Count 
) 

SELECT Column1, Column2, Column3, Column4, Column5 
FROM tally 
LEFT JOIN 
(
    SELECT Column1, ROW_NUMBER() OVER (ORDER BY Column1) rn 
    FROM 
    (
     SELECT DISTINCT Column1 
     FROM YourTable 
    ) t1 
) d1 ON(n = d1.rn) 
LEFT JOIN 
(
    SELECT Column2, ROW_NUMBER() OVER (ORDER BY Column2) rn 
    FROM 
    (
     SELECT DISTINCT Column2 
     FROM YourTable 
    ) t1 
) d2 ON(n = d2.rn) 
LEFT JOIN 
(
    SELECT Column3, ROW_NUMBER() OVER (ORDER BY Column3) rn 
    FROM 
    (
     SELECT DISTINCT Column3 
     FROM YourTable 
    ) t1 
) d3 ON(n = d3.rn) 
LEFT JOIN 
(
    SELECT Column4, ROW_NUMBER() OVER (ORDER BY Column4) rn 
    FROM 
    (
     SELECT DISTINCT Column4 
     FROM YourTable 
    ) t1 
) d4 ON(n = d4.rn) 
LEFT JOIN 
(
    SELECT Column5, ROW_NUMBER() OVER (ORDER BY Column5) rn 
    FROM 
    (
     SELECT DISTINCT Column5 
     FROM YourTable 
    ) t1 
) d5 ON(n = d5.rn) 

Dynamische Version:

DECLARE @TableName sysname = 'YourTableName' 

DECLARE @Sql nvarchar(max) = 
' 
DECLARE @Count int 
select @Count = COUNT(1) 
FROM '+ @TableName +' 

;with tally as (
    select 1 as n 
    union all 
    select n + 1 
    from tally 
    where n < @Count 
) 

SELECT ' 

SELECT @Sql = @Sql + Column_Name +',' 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = @TableName 

SELECT @Sql = LEFT(@Sql, LEN(@Sql) - 1) + ' FROM tally t' 

SELECT @Sql = @Sql + ' LEFT JOIN (SELECT '+ Column_Name +', ROW_NUMBER() OVER (ORDER BY ' + Column_Name +') rn 
    FROM 
    (
    SELECT DISTINCT '+ Column_Name +' FROM '+ @TableName +') t 
) c_'+ Column_Name + ' ON(n = c_'+ Column_Name + '.rn)' 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = @TableName 

EXEC(@Sql) 

aktualisieren

auf einen Tisch Getestet mit 22 Spalten und 47.000 Zeilen, nahm mein Vorschlag 46 Sekunden, wenn ein proper tally table. auf SQL Server 2014 verwenden Ich war überrascht - ich dachte es würde mindestens 2-3 Minuten dauern.

+0

Sie sind fast da. Jetzt mach es dynamisch. :-P –

+0

Dies zu einem dynamischen SQL zu machen ist nicht so schwer, aber ich bezweifle, dass es besser sein wird als die dynamische Lösung, die Kahn in der anderen Antwort vorgeschlagen hat. –

+0

@ JeroenMostert: Challenge freigestellt. –

1

Hier ist ein dynamisches Set, an dem ich gearbeitet habe. Mir läuft die Zeit davon, so dass sie nicht aufgeräumt wird, und sie bestimmt die Anzahl dynamischer Zeilen anhand der maximalen Anzahl von Zeilen in der Tabelle als Ganzes, was bedeutet, dass Du, wenn Du überhaupt Duplikate in irgendeiner Spalte hast links mit Zeilen, in denen jede einzelne Spalte null ist.

Aber ansonsten sollte das perfekt funktionieren, und das Skript enthält die notwendigen Informationen, die Ihnen zeigen, wie Sie einen abschließenden "WHERE S1.COLNAME IS NOT NULL UND S2.COLNAME IST NOT NULL AND .." Filter zu verketten die Ergebnistabelle, um diese Voll-Null-Zeilen zu eliminieren.

Abgesehen davon, hier ist das Skript. Es wird offensichtlich schwer, also habe ich einen Hinweis (nolock) eingefügt und einen "WHERE ColName ist nicht null", um nutzlose Ergebnisse zu entfernen.

Versuchen Sie dies auf einer kleineren Tabelle und sehen Sie, wie es funktioniert.

/* 
Set your table and schema on @MYTABLE and @MYSCHEMA variables. 
*/ 
SET NOCOUNT ON 

DECLARE @MYTABLE SYSNAME = 'Mytablename here' 
    , @MYSCHEMA sysname = 'dbo' 

DECLARE @SQL NVARCHAR(MAX) = '', @COLNAME sysname = '', @MYCOLS NVARCHAR(max) = '' 

DECLARE @COL_NOW INT = 1, @COL_MAX INT = 
    (SELECT COUNT(*) 
    FROM sys.columns 
    WHERE object_id = (SELECT object_id FROM sys.tables where name = @MYTABLE and SCHEMA_NAME(schema_id) = @MYSCHEMA)) 

SELECT @COLNAME = name 
    FROM sys.columns 
    WHERE column_id = 1 
    and object_id = (SELECT object_id FROM sys.tables where name = @MYTABLE and SCHEMA_NAME(schema_id) = @MYSCHEMA) 

SET @SQL = 'FROM 
    (SELECT ROW_NUMBER() OVER (ORDER BY '[email protected]+' ASC) RN 
    FROM '[email protected]+'.'[email protected]+' (nolock)) S' 

WHILE @COL_NOW <= @COL_MAX 
BEGIN 

    SELECT @COLNAME = name 
    FROM sys.columns 
    WHERE column_id = @COL_NOW 
    and object_id = (SELECT object_id FROM sys.tables where name = @MYTABLE and SCHEMA_NAME(schema_id) = @MYSCHEMA) 

    SELECT @SQL = @SQL+' 
FULL JOIN 
    (SELECT DISTINCT DENSE_RANK() OVER (ORDER BY '[email protected]+' ASC) RN, '[email protected]+' 
    FROM '[email protected]+'.'[email protected]+' (nolock) 
    WHERE '[email protected]+' IS NOT NULL) S'+CAST(@COL_NOW AS NVARCHAR(25))+' ON S'+CAST(@COL_NOW AS NVARCHAR(25))+'.RN = S.RN' 

    IF @COL_NOW = 1 
     SELECT @MYCOLS = @MYCOLS+' S'+CAST(@COL_NOW AS NVARCHAR(25))+'.'[email protected]   
    ELSE 
     SELECT @MYCOLS = @MYCOLS+', S'+CAST(@COL_NOW AS NVARCHAR(25))+'.'[email protected] 

    SET @COL_NOW = @COL_NOW+1 

END 

SELECT @SQL = 'SELECT'[email protected]+' 
'[email protected]+' 
ORDER BY S1.RN ASC'; 

--PRINT(@SQL); -- To check resulting dynamic SQL without executing it (Warning, print will only show first 8k characters) 

EXEC sp_executesql @SQL; 
GO 
Verwandte Themen