2012-05-25 25 views
5

Tôi có một truy vấn OracleSQL Server: làm thế nào để bắt chước oracle giữ truy vấn dense_rank?

select max(m.id), 
     m.someId keep (DENSE_RANK FIRST ORDER BY m.UpdateDate desc) 
from MyTable m 
groupBy m.someId 

mà cho dữ liệu như thế này:

id UpdateDate someId 
1 20-01-2012 10 
2 20-01-2012 10 
3 01-01-2012 10 
4 10-02-2012 20 
5 01-02-2012 20 
6 01-04-2012 30 

sẽ trở lại cho tôi chính xác này:

2 10 
4 20 
6 30 

Vì vậy, đối với mỗi someId nó tìm kiếm UpdateDate mới nhất và trả lại id thích hợp. (Và nếu có một số id cho những ngày mới nhất nó có id mới nhất).

Nhưng đối với máy chủ SQL, truy vấn này có hoạt động giống nhau không? Ý tôi là xây dựng này keep (dense_rank first order by ..)?

Trả lời

8

Tôi không nghĩ rằng truy vấn cụ thể của bạn sẽ chạy SQL Server. Nhưng bạn có thể đạt được kết quả tương tự làm điều này:

SELECT id, SomeId 
FROM ( SELECT *, ROW_NUMBER() OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) Corr 
     FROM MyTable) A 
WHERE Corr = 1 
+0

tôi không nhận được nó .. làm thế nào nó phải làm việc mà không có 'nhóm bởi someId'? Truy vấn của tôi sẽ luôn trả lại cho tôi 3 mục khi tôi có 3 phần tử khác nhau trong bảng. Truy vấn của bạn sẽ trả lại kết quả không phụ thuộc vào số lượng các phần tử khác nhau, do đó, nó sẽ là sai sau đó? – javagirl

+1

@javagirl - Bạn đã thử nó trước chưa ?, nó sẽ hoạt động. Về cách thức hoạt động, các hàm phân tích ('OVER() ...') có thể có 'PARTITION BY' và không cần nhóm trên toàn bộ cấp độ. Nó trả về một giá trị cho mỗi hàng nằm trên bàn. – Lamak

+0

Tôi đã đọc sai dữ liệu gốc. Vấn đề được cố định bằng cách đặt someid vào phân vùng thay vì id. –

1

SQL Server không hỗ trợ "giữ" xây dựng, vì vậy bạn cần phải sử dụng một subquery:

select m.* 
from (select *, row_number() over (partition by m.someid ORDER BY m.UpdateDate desc) as seqnum 
     from MyTable m 
    ) m 
where seqnum = 1 

này thấy hàng đầu tiên cho mỗi m.id với UpdateDate gần đây nhất. Sau đó, chọn hàng đó trong truy vấn bên ngoài. Lưu ý rằng bạn không cần nhóm bằng phương pháp này.

+0

Tôi không hiểu ... làm sao nó hoạt động mà không có 'nhóm bởi someId' ? Truy vấn của tôi sẽ luôn trả lại cho tôi 3 mục khi tôi có 3 phần tử khác nhau trong bảng. Truy vấn của bạn sẽ trả lại kết quả không phụ thuộc vào số lượng các phần tử khác nhau, do đó, nó sẽ là sai sau đó? – javagirl

+0

Điều này sẽ không hoạt động, bạn sẽ có một hàng cho mỗi id là kết quả, và đó không phải là những gì op muốn. – Lamak

3

Tôi quay lại và trả lời câu hỏi này và câu trả lời. Rất tiếc, có một số trường hợp khi di chuyển bằng cách sử dụng "chức năng cửa sổ để xếp hạng" trở nên rất phức tạp. Những tình huống này là:

  1. nhiều công trình xây dựng KEEP-DENSE_RANK ở phần chọn của Oracle truy vấn dựa trên đơn đặt hàng khác nhau
  2. nhóm bằng cách nhóm các bộ/rollups

Vì vậy, tôi sẽ thêm vào câu trả lời thêm thông tin. SQLFIDDLE dữ liệu gốc: http://sqlfiddle.com/#!6/e5c6d/6

1. Reading oracle chức năng:

select max(m.id), m.someId keep (DENSE_RANK FIRST ORDER BY m.UpdateDate desc) 
from MyTable m 
groupBy m.someId 

đó chúng tôi chọn tối đa của m.id trong nhóm (someId, UpdateDate), nơi UpdateDate là lớn nhất đó nhóm (someId)

2. thẳng về phía trước cách không hoạt động vì lỗi: Cột 'MyTable.UpdateDate' không hợp lệ trong các lựa chọn liệt kê vì nó không được chứa trong hàm tổng hợp hoặc mệnh đề GROUP BY.

SELECT FIRST_VALUE(id) OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) first_in_orderedset , someId 
FROM MyTable 
GROUP BY someId 

3. improoved 'thẳng về phía trước' là noneffective

SELECT someId, MIN(first_in_orderedset) 
FROM 
(SELECT FIRST_VALUE(id) OVER(PARTITION BY someId ORDER BY UpdateDate DESC, id DESC) first_in_orderedset , someId 
    FROM MyTable) t 
GROUP BY someId; 

4. chéo áp dụng:

SELECT grouped.someId, orderedSet.FirstUpdateDate, maxInSet.first_in_orderedset FROM 
(
    SELECT mt.someId 
    FROM MyTable mt 
    GROUP BY mt.someId 
) grouped CROSS APPLY 
( 
    SELECT top 1 mt2.UpdateDate as FirstUpdateDate 
    FROM MyTable mt2 
    WHERE mt2.someId=grouped.someId 
    ORDER BY UpdateDate desc 
) orderedSet CROSS APPLY 
( 
    SELECT max(mt3.id) as first_in_orderedset 
    FROM MyTable mt3 
    WHERE mt3.someId=grouped.someId and mt3.UpdateDate=orderedSet.FirstUpdateDate 
) maxInSet; 

5. Bây giờ cho phép có được bảng phức tạp hơn và truy vấn phức tạp hơn: ORACLE: http://sqlfiddle.com/#!4/c943c/23 SQL SERVER: http://sqlfiddle.com/#!6/dc7fb/1/0 (dữ liệu được pregenerated và nó là như nhau trong cả hai Hố cát - nó rất dễ dàng để so sánh kết quả) Bảng:

CREATE TABLE AlarmReports (
    id int PRIMARY KEY, 
    clientId int, businessAreaId int , projectId int, taskId int, 
    process1Spent int, process1Lag int, process1AlarmRate varchar2(1) null, 
    process2Spent int, process2Lag int, process2AlarmRate varchar2(1) null, 
    process3Spent int, process3Lag int, process3AlarmRate varchar2(1) null 
) 

Oracle truy vấn:

SELECT clientId, businessAreaId, projectId, 
    sum(process1Spent), 
    sum(process2Spent), 
    sum(process3Spent), 
    MIN(process1AlarmRate) KEEP (DENSE_RANK FIRST ORDER BY process1Lag DESC), 
    MIN(process2AlarmRate) KEEP (DENSE_RANK FIRST ORDER BY process2Lag DESC), 
    MIN(process3AlarmRate) KEEP (DENSE_RANK FIRST ORDER BY process3Lag DESC) 
FROM AlarmReports 
GROUP BY GROUPING SETS ((),(clientId),(clientId, projectId),(businessAreaId),(clientId,businessAreaId)) 

truy vấn SQL:

(to be continued) 

thực sự ở đó tôi đã lên kế hoạch để đưa tổng hợp tùy chỉnh của tôi wroted với C#. nếu ai đó quan tâm, xin vui lòng liên hệ với tôi ... tổng hợp tùy chỉnh là giải pháp tốt nhất của vấn đề như vậy nhưng nó không phải là unviersal về độ dài varchar. cho mỗi chiều dài varchar, bạn sẽ có nghĩa vụ tạo ra chức năng aggreate "chuyên biệt"

0

Điều đó sẽ hoạt động hoàn toàn. Hãy thử đầu tiên, sau đó tranh luận. Khi bạn có nhiều đơn đặt hàng của bạn có thể làm điều này (ví dụ thực hiện trên Oracle):

- một trong những điều này với giữ DENSE_RANK

WITH a AS (SELECT 1 s1, 4 s2, 'a' c, 10 g FROM dual UNION all 
      SELECT 2 s1, 2 s2, 'b' c, 10 g FROM dual UNION ALL 
      SELECT 3 s1, 1 s2, 'c' c, 20 g FROM dual UNION ALL 
      SELECT 4 s1, 3 s2, 'd' c, 20 g FROM dual) 
SELECT g, 
     MAX(c) KEEP (DENSE_RANK FIRST ORDER BY s1) s1, 
     MAX(c) KEEP (DENSE_RANK FIRST ORDER BY s2) s2 
    FROM a 
GROUP BY g 

- Đây một mà không giữ DENSE_RANK

WITH a AS (SELECT 1 s1, 4 s2, 'a' c, 10 g FROM dual UNION all 
       SELECT 2 s1, 2 s2, 'b' c, 10 g FROM dual UNION ALL 
       SELECT 3 s1, 1 s2, 'c' c, 20 g FROM dual UNION ALL 
       SELECT 4 s1, 3 s2, 'd' c, 20 g FROM dual) 
SELECT g, 
     MAX(DECODE(s1, 1, c)) s1, 
     MAX(DECODE(s2, 1, c)) s2 
    FROM (SELECT g,c, 
       ROW_NUMBER() OVER (PARTITION BY g ORDER BY s1) s1, 
       ROW_NUMBER() OVER (PARTITION BY g ORDER BY s2) s2 
      FROM a) b 
GROUP BY g 
Các vấn đề liên quan