2009-06-09 18 views
23

Jak powiązać wszystkie wartości kolumn z różnicowych wierszy zwróconych przez zapytanie sql do jednej wartości? To jest przykład:Skonsultuj wszystkie wartości kolumn w sql

zapytaniu powraca:

 
FOO 
------ 
RES1 

RES2 

RES3 

teraz chcę mieć wynik podobny do następującego:

 
FOOCONCAT 
----- 
RES1RES2RES3 

czy są jakieś sposoby, aby to zrobić w SQL?

+0

Która serwer używasz? Wątpię, czy istnieje ogólna metoda SQL, ale z pewnością istnieją konkretne metody implementacji. –

+1

Używam Oracle. Jestem zdumiony, że nie ma łatwego sposobu na zrobienie tego w wyroczni. – paweloque

Odpowiedz

0
select cast(res1 as varchar)+cast(res2 as varchar)+cast(res3 as varchar) as fooconcat from foo 

Jeśli kolumny są już struny nie trzeba do obsady, można po prostu zrobić:

select res1 + res2 + res3 as fooconcat from foo 

Dla danych z wielu wierszy, użyj PIVOT.

+0

i jak zrobić to samo dla dowolnej liczby wartości? – paweloque

+0

res1, res2 i res3 nie są kolumnami, ale wartościami. Kolumna to "foo". – paweloque

+0

Niestety, kiedy odpowiedziałem, twoje dane zostały sformatowane w jednym wierszu, więc pytanie okazało się inne. – RedFilter

40

W SQL Server:

SELECT col1 AS [text()] 
FROM foo 
FOR XML PATH ('') 

W MySQL:

SELECT GROUP_CONCAT(col1 SEPARATOR '') 
FROM foo 

W PostgreSQL:

SELECT array_to_string 
     (
     ARRAY 
     (
     SELECT col1 
     FROM foo 
     ), '' 
     ) 

W Oracle:

SELECT * 
FROM (
     SELECT col1, ROW_NUMBER() OVER(ORDER BY 1) AS rn 
     FROM foo 
     MODEL 
     DIMENSION BY 
       (rn) 
     MEASURES 
       (col1, col1 AS group_concat, 0 AS mark) 
     RULES UPDATE (
       group_concat[rn > 1] = group_concat[CV() - 1] || col1[CV()], 
       mark[ANY] = PRESENTV(mark[CV() + 1], 0, 1) 
       ) 
     ) 
WHERE mark = 1 
+1

wygląda jak rozwiązanie, ale jak by to wyglądało w wyroczni? – paweloque

+1

@lewap: Patience! – Quassnoi

+0

To fajna sztuczka w SQL Server, po prostu zmieniłabym zaznaczenie na: WYBÓR REPLACE (REPLACE (col1, '', ''), '', '') – RedFilter

0

Konkatenowanie struny zależy od używanej bazy danych (ty havnt wspomniano co wersja w swoim pytaniu, tak tu idzie) ...

W Oracle i DB2 można użyć funkcji CONCAT ... CONCAT(string, string)

SQL Server można użyć operatora '+' ... string1 + string2 + string3

w MySQL jest CONCAT(string, string... n_string)

Wreszcie w PostgreSQL jest TEXTCAT(string, string) ...

... Dostałem to z tej małej fajnej książki, którą siedzę na biurku. Przewodnik kieszonkowy SQL od O'Reilly ... sprawdź to!

:)

+1

Te działają tylko z ciągami z tego samego wiersza. –

+0

Wiem, co masz na myśli, zrobiłbyś coś takiego ... Wybierz @ TEXT = @Text + RES lub Select @Text = CONCAT (@Text, RES) itd., Aby połączyć kolumny. –

3

Zakładając, że jest to jedna kolumna z wielu wartości, takie podejście działa dla MS SQL Server (nie mogę mówić za innych systemów).

declare @result varchar(max) 
set @result = '' 

select @result = @result + RES 
from (query goes here) 
0

To nie może być to, czego szukasz, ale miałem szczęście w przeszłości z konstrukcji tak:

SELECT  MAX(DECODE(fookey, 1, foo, NULL)) 
     || MAX(DECODE(fookey, 2, foo, NULL)) 
     || MAX(DECODE(fookey, 3, foo, NULL)) 
     || MAX(DECODE(fookey, 4, foo, NULL)) 
     , groupingvalue 
    FROM mytable 
GROUP BY groupingvalue; 

Jest to niezależne od platformy i działa dobrze, kiedy mają dowolną, ale ograniczoną liczbę wartości dla foo i opierają się na innej wartości klucza.Jeśli na przykład masz tabelę faktur i chcesz zobaczyć wszystkie czasy liniowe z faktury w jednym wierszu, połączone i masz górny limit 5 elementów zamówienia, wyglądałoby to tak:

SELECT  MAX(DECODE(lineno, 1, foo, NULL)) 
     || ', ' 
     || MAX(DECODE(lineno, 2, foo, NULL)) 
     || ', ' 
     || MAX(DECODE(lineno, 3, foo, NULL)) 
     || ', ' 
     || MAX(DECODE(lineno, 4, foo, NULL)) 
     || ', ' 
     || MAX(DECODE(lineno, 5, foo, NULL)) 
     , invoiceid 
    FROM lineitem 
GROUP BY invoiceid; 
3

MySQL sposób:

select group_concat(somecolumn separator '') from sometable 
+0

okazało się nie całkiem tym, czego potrzebowałem, ale mogę powiedzieć, że to będzie naprawdę przydatne kiedyś. – jsh

1

Oto odpowiedź szukasz; Miałem wrażenie, że rozwiązanie leży w operacji CONNECT BY, po prostu nie użyłem wcześniej pseudokolumny SYS_CONNECT_BY_PATH (która wyświetla pełną ścieżkę do węzła w drzewie, oddzielając nazwy węzłów przez "/"). Zakładając, że zestaw wartości „foo” przed wiele wierszy w tabeli, pogrupowane według kolumny „MyKey”, np:

myKey foo 
-------- ---------- 
group 1 apple 
group 1 orange 
group 1 pear 
group 2 ape 
group 2 bear 
group 2 kitten 

można traktować dane tak, jakby to był schemat drzewa, i udawać, że wartości każdej grupy reprezentują węzły przechodzące przez gałąź. W takim przypadku można to zrobić:

SELECT myKey 
     , SUBSTR(MAX(REPLACE(SYS_CONNECT_BY_PATH(foo, '/') 
          ,'/' 
          ,' ' 
          ) 
        ) 
       ,2 
       ) FooConcat 
    FROM (SELECT MyKey 
       , Foo 
       , row_number() OVER (Partition by myKey order by myKey) NodeDepth 
      FROM MyTable 
     ) 
    START WITH NodeDepth = 1 
CONNECT BY PRIOR myKey = myKey 
    AND PRIOR NodeDepth = NodeDepth -1 
GROUP BY myKey 
; 

Oczywiście porządek połączonych wartości byłby losowy; jeśli Twój stół miał inną kolumnę ("słupek"), który mógłbyś użyć jako pole porządkowe, które było rosnące i przylegające, możesz zrezygnować z podzapytania (które istnieje tylko po to, aby umieścić wyimaginowaną głębię w drzewie) i użyć bezpośrednio tabeli, zastępując NodeDepth za pomocą paska.

8

Rozwiązania Oracle firmy Quassnoi są imponujące, ale I foundsimpler używają SYS_CONNECT_BY_PATH() zamiast magii MODEL.

SELECT REPLACE(MAX(SYS_CONNECT_BY_PATH(foo, '/')), '/', '') conc 
FROM (
    SELECT T_FOO.*, ROW_NUMBER() OVER (ORDER BY FOO) R FROM T_FOO 
) 
START WITH r=1 
CONNECT BY PRIOR r = r-1; 
+0

Miło, udało mi się z tego skorzystać. Dobra robota. – contactmatt

-2

Wybierz ([kol1] + ' '+ [kolumna2] +', '+ [Col3] +',' + [Col4]), w [Mycol] Z [Tabela]

+3

celem jest łączenie wierszy, a nie kolumn –

1

Edycja: Od wersji 8.4.0 CUBRID zapewnia 90% compatibility z MySQL. W ten sposób wspiera GROUP_CONCAT który ma podobną składnię jak w MySQL:

CREATE TABLE t(i int); 
INSERT INTO t VALUES (4),(2),(3),(6),(1),(5); 

SELECT GROUP_CONCAT(i*2+1 ORDER BY 1 SEPARATOR '') FROM t; 

group_concat(i*2+1 order by 1 separator '') 
====================== 
    '35791113' 

Dość mocny, prawda? Poniżej znajduje się alternative solution obsługiwana natywnie w CUBRID.

SELECT MAX(SYS_CONNECT_BY_PATH(s_name, '')) AS conc_s_name 
FROM (
    SELECT ROWNUM AS r, s_name FROM code 
) AS res 
START WITH r = 1 
CONNECT BY PRIOR r = r - 1; 

To tak ciekawe, że ten sposób łącząc różne wartości kolumn wiersz CUBRID jest niemal identyczny sposób jak Oracle zapewnia @devio. W CUBRID wygląda jednak trochę łatwiej.

0

SQL Server 2008 R2:

declare @ColumnNameList VARCHAR(MAX) 


SELECT @ColumnNameList = COALESCE(@ColumnNameList +',' ,'') + ColumnName 
        FROM 
         <<table name>> 

select @ColumnNameList 
Powiązane problemy