2009-05-20 67 views
5

Chúng tôi có một bảng mà có dạng:Độc SQL SELECT Trở nhiều hàng từ một bảng hàng

ID,Value1,Value2,Value3 
1,2,3,4 

Chúng ta cần phải chuyển đổi này vào.

ID,Name,Value 
1,'Value1',2 
1,'Value2',3 
1,'Value3',4 

Có cách thông minh để thực hiện điều này trong một câu lệnh SELECT (nghĩa là không có UNION) không? Tên cột Value1, Value2 và Value3 là cố định và không đổi.

Cơ sở dữ liệu là oracle 9i.

+0

Bạn đang sử dụng máy chủ DB nào? –

+0

Có 1,2,3,4 cột hoặc giá trị dữ liệu không? –

+1

Cách thông minh nhất mà tôi có thể nghĩ đến là thiết kế lại cơ sở dữ liệu của bạn để nó được chuẩn hóa :) –

Trả lời

3

này hoạt động trên Oracle 10g:

select id, 'Value' || n as name, 
     case n when 1 then value1 when 2 then value2 when 3 then value3 end as value 
from (select rownum n 
     from (select 1 from dual connect by level <= 3)) ofs, t 

Tôi nghĩ rằng Oracle 9i có truy vấn đệ quy? Dù sao, tôi khá chắc chắn nó có hỗ trợ CASE, vì vậy ngay cả khi nó không có truy vấn đệ quy, bạn chỉ có thể làm "(chọn 1 từ công đoàn kép tất cả chọn 2 từ công đoàn kép tất cả chọn 3 từ kép) của" thay thế. Lợi dụng các truy vấn đệ quy tổng quát hơn một chút đối với Oracle. (Tuy nhiên, việc sử dụng các công đoàn để tạo các hàng có thể di chuyển sang các DB khác)

+0

+1 để quét bảng đơn. Truy vấn đệ quy WRT - Oracle đã có các truy vấn phân cấp từ 7, nhưng chỉ giới thiệu mệnh đề WITH đệ quy trong 11gR2. –

9

Tặng union một lần chụp.

select ID, 'Value1' as Name, Value1 as Value from table_name union all 
select ID, 'Value2', Value2 as Value from table_name union all 
select ID, 'Value3', Value3 as Value from table_name 

order by ID, Name 

sử dụng union all nghĩa là máy chủ sẽ không thực hiện một distinct (đó là tiềm ẩn trong union hoạt động). Nó sẽ không tạo ra bất kỳ sự khác biệt nào với dữ liệu (vì ID của bạn nên HOPEFULLY khác nhau), nhưng nó có thể tăng tốc nó một chút.

+0

Tốt, đó là cách tôi sẽ làm - tôi thích tối ưu hóa UNION ALL. Lỗi nhỏ trong ví dụ không có giá trị 4. Tôi đoán một cách khác là để tháo rời, tùy thuộc vào việc DB có hỗ trợ chức năng này hay không. – RichardOD

+0

Sử dụng 'union all' chắc chắn sẽ không tạo ra bất kỳ sự khác biệt nào với kết quả đầu ra vì 'Value1', 'Value2' và 'Value3' đều khác nhau! Nhưng nó sẽ tránh DB vô dụng cố gắng để thống nhất các hàng. – araqnid

+0

Câu trả lời hay, nhưng câu hỏi được hỏi theo cách * không có * công đoàn! –

2

Bạn có thể làm điều đó như thế này, nhưng nó không đẹp:

SELECT id,'Value 1' AS name,value1 AS value FROM mytable 
UNION 
SELECT id,'Value 2' AS name,value2 AS value FROM mytable 
UNION 
SELECT id,'Value 3' AS name,value3 AS value FROM mytable 
2

Unioning ba câu chọn nên làm các trick:

SELECT ID, 'Value1', Value1 AS Value 
FROM TABLE 
UNION 
SELECT ID, 'Value2', Value2 AS Value 
FROM TABLE 
UNION 
SELECT ID, 'Value3', Value3 AS Value 
FROM TABLE 
0

Nếu bạn đang sử dụng SQL Server 2005 + sau đó bạn có thể sử dụng UNPIVOT

CREATE TABLE #tmp (ID int, Value1 int, Value2 int, Value3 int) 

INSERT INTO #tmp (ID, Value1, Value2, Value3) VALUES (1, 2, 3, 4) 

SELECT 
    * 
FROM 
    #tmp 

SELECT 
    * 
FROM 
    #tmp 
UNPIVOT 
(
    [Value] FOR [Name] IN (Value1, Value2, Value3) 
) uPIVOT 

DROP TABLE #tmp 
-1

Đối với Sql server, hãy xem xét UNPIVOT như một thay thế cho UNION:

SELECT id, value, colname 
FROM #temp t 
UNPIVOT (Value FOR ColName IN (value1,value2,value3)) as X 

Điều này cũng sẽ trả về tên cột. Tôi không chắc chắn những gì X được sử dụng cho, nhưng bạn không thể để nó ra.

0

UNION ALL, như những người khác đã đề xuất, có lẽ là đặt cược tốt nhất của bạn trong SQL. Bạn cũng có thể xem xét việc xử lý điều này trong giao diện người dùng tùy thuộc vào yêu cầu cụ thể của bạn.

-1

Hãy thử điều này:

CTE tạo bảng tạm thời có 4 giá trị. Bạn có thể chạy nó như trong bất kỳ cơ sở dữ liệu nào.

with TEST_CTE (ID) as 

(select * from (select '1' as a) as aa union all 
select * from (select '2' as b) as bb union all 
select * from (select '3' as c) as cc union all 
select * from (select '4' as d) as dd) 

select a.ID, 'Value'|| a.ID, b.ID 
from TEST_CTE a, TEST_CTE b 
where b.ID = (select min(c.ID) from TEST_CTE c where c.ID > a.ID) 

Dưới đây là tập hợp kết quả:

1 Value1 2 

2 Value2 3 

3 Value3 4 

Thưởng thức!

Một số suy nghĩ.

^^^ Cú pháp CTE có thể khác trong Oracle. Tôi chỉ có thể chạy nó trong Teradata. Bạn có thể thay thế nó bằng bảng tạm thời hoặc sửa cú pháp để làm cho nó tương thích với Oracle. Câu lệnh chọn là SQL vanilla thuần tuý sẽ hoạt động trên bất kỳ cơ sở dữ liệu nào.

^^^ Một điều cần lưu ý khác. Nếu trường ID là số, bạn có thể cần phải nhập nó vào CHAR để nối nó với "Giá trị".

+0

-1 Điều này không chạy trên Oracle. –

+0

Tôi vừa thêm một số nhận xét vào bài đăng của mình. –

0

Cú pháp CTE có thể khác với Oracle (tôi đã chạy nó trong Teradata), nhưng tôi chỉ sử dụng CTE để cung cấp dữ liệu thử nghiệm, 1 2 3 và 4. Bạn có thể sử dụng bảng tạm thời thay thế. Câu lệnh chọn thực tế là SQL vanilla đơn giản và nó sẽ nằm trên bất kỳ cơ sở dữ liệu quan hệ nào.

Các vấn đề liên quan