2012-08-23 33 views
5

Tôi có bảng được cập nhật bằng cách sử dụng các bản ghi của bảng khác và tôi đang thực hiện việc này để mang lại thông tin từ một hệ thống (cơ sở dữ liệu) sang hệ thống khác. Kịch bản là chút phức tạp, nhưng tôi rất cần giúp :-sSQL INNER QUERY trả về nhiều giá trị trong truy vấn UPDATE

Có 3 bảng - component, scanstage_link

phần

component_id stage_id 
------------ -------- 
1    NULL 
2    NULL 
3    NULL 
4    NULL 
5    NULL 

quét

scan_id component_id scanner_id   date_scanned 
------- ------------ ---------- ----------------------- 
1   1   scanner_a 2012-01-01 07:25:15.125 
2   1   scanner_b 2012-01-02 08:14:05.456 
3   2   scanner_a 2012-01-01 12:05:45.465 
4   3   scanner_a 2012-01-01 19:45:12.536 
5   1   scanner_c 2012-01-03 23:33:54.243 
6   2   scanner_b 2012-01-02 11:59:12.545 

stage_link

stage_link_id scanner_id stage_id 
    -------  ---------- ---------- 
     1   scanner_a 1 
     2   scanner_b 1  
     3   scanner_c 2  
     4   scanner_d 2  
     5   scanner_e 2 
     6   scanner_f 3 

tôi cần phải update bàn componentset lĩnh vực này stage_id theo quá trình quét mới nhất. Mỗi lần quét sẽ đưa thành phần vào một giai đoạn theo máy quét liên quan. Tôi đã viết truy vấn sau đây để update bảng component, nhưng nó ném một lỗi nói;

Subquery returned more than 1 value. This is not permitted when the subquery follows '='

Truy vấn là;

UPDATE component 
SET stage_id = (select stage_id 
       from(
        select scn.scanner_id, sl.stage_id 
        from scan scn 
        INNER JOIN stage_link sl ON scn.scanner_id = sl.scanner_id 
        where scn.date_scanned = ( select temp_a.max_date 
               from ( SELECT x.component_id, MAX(x.date_scanned) as max_date 
                 FROM scan x 
                 where component_id = x.component_id 
                 GROUP BY x.component_id 
                ) as temp_a 
               where component_id = temp_a.component_id) 
        ) as temp_b 
       ) 

Tôi đang làm việc theo số MS SQL Server và muốn sắp xếp điều này bằng cách sử dụng số PHP hoặc bất kỳ ngôn ngữ nào khác.

Tôi đã thử một ngày để thực hiện công việc này nhưng vẫn không có cách nào để thực hiện công việc này. Bất cứ sự giúp đỡ nào cũng được đánh giá cao!

Cảm ơn bạn rất nhiều trước :-)

Trả lời

4

Kiểm tra điều này mà không cần sử dụng truy vấn con tương ứng:

UPDATE Com 
SET  stage_id = Temp4.stage_id 
FROM dbo.component Com 
     INNER JOIN 
     ( 
      SELECT Temp2.component_id ,SL.stage_id 
      FROM dbo.stage_link SL 
      INNER JOIN (
          SELECT component_id ,scanner_id 
          FROM scan 
          WHERE date_scanned IN (
           SELECT MaxScanDate 
           FROM  
           ( 
            SELECT component_id , MAX(date_scanned) MaxScanDate 
            FROM scan 
            GROUP BY component_id 
           ) Temp 
          ) 
         ) Temp2 ON Temp2.scanner_id = SL.scanner_id 
     ) Temp4 ON Com.component_id = Temp4.component_id 

Sản lượng:

component_id stage_id 
------------ ----------- 
1   2 
2   1 
3   1 
4   NULL 
5   NULL 
+0

Cảm ơn bạn rất nhiều vì gợi ý này !! nó đến giúp đỡ rất nhiều !! Đây chính là điều tôi muốn !!! :-) cảm ơn bạn rất nhiều một lần nữa!!!!! – mithilatw

+0

@mithilatw: Bạn được chào đón. Xin lưu ý rằng có thể có 2 vấn đề với truy vấn này (để tham khảo trong tương lai): (1) Điều này giả định rằng date_scanned luôn là duy nhất. Nếu 2 máy quét quét cùng một lúc (tối đa phần nano giây), thì 'SELECT component_id, scanner_id' sẽ trả về 2 giá trị. (2) Các trường trong tham gia 'Temp2.scanner_id = SL.scanner_id' là các cột dựa trên char, do đó nếu bạn có nhiều scanner_ids, thì truy vấn này có thể bắt đầu chậm lại. – Kash

2

Vâng, truy vấn con của bạn đang trả về nhiều giá trị. Một cách dễ dàng là thực hiện tổng hợp:

SET stage_id = (select max(stage_id) 
. . . 

Lý do có thể là do có nhiều lần quét vào ngày gần đây nhất. Vì bạn chỉ có thể chọn một, cho ngữ cảnh, sau đó MIN hoặc MAX là đủ.

Tuy nhiên, tôi nghĩ lý do thực sự là bạn không có bí danh phù hợp cho truy vấn con tương quan. Tôi nghĩ rằng những dòng này:

where component_id = x.component_id 
where component_id = temp_a.component_id 

nên bao gồm các bí danh, có lẽ là:

where component.component_id = x.component_id 
where component.component_id = temp_a.component_id 

Nếu đây là không đủ, bạn cần phải giải thích những gì bạn muốn. Bạn có muốn truy vấn trả lại một lần quét ngẫu nhiên từ ngày gần đây nhất không? Bạn có muốn cập nhật thành phần cho tất cả các lần quét vào ngày gần đây nhất không?

Bạn cần điều tra thêm về điều này.Hãy thử một cái gì đó như thế này:

select scn.scanner_id, sl.stage_id, count(*) 
from scan scn INNER JOIN 
    stage_link sl 
    ON scn.scanner_id = sl.scanner_id join 
    (SELECT x.component_id, 
      MAX(x.date_scanned) as max_date 
     FROM scan x 
     GROUP BY x.component_id 
    ) cmax 
    on scn.component_id = cmax.component_id 
where scn.date_scanned = cmax.maxdate 
group by scn.scanner_id, sl.stage_id 
order by count(*) desc 
+0

Cảm ơn bạn rất nhiều vì câu trả lời !! Tôi đang cố gắng cập nhật tất cả các thành phần của bảng 'thành phần' bằng cách xem xét các lần quét được thực hiện trên một thành phần tại một thời điểm. Do đó, chỉ có thể quét một lần vào ngày 'max' khi' được nhóm theo'. Vấn đề với đề xuất của bạn là độ chính xác của thông tin. Và giá trị số tối đa của 'stage_id' không phải là giai đoạn mới nhất mà thành phần có thể là (xin lỗi kịch bản này phức tạp lắm!) Vấn đề của tôi là, chỉ có thể quét một lần vào ngày' max' cho mỗi thành phần và nó vẫn trả về nhiều hơn 1 :-( – mithilatw

+1

@mithilatw ... Hãy truy vấn con ra khỏi bản cập nhật và bắt đầu điều tra vị trí trùng lặp xảy ra.Nó có thể trùng lặp trong một trong các bảng theo scanner_id hoặc theo thành phần. trùng lặp vào cùng một ngày là một thủ phạm rất có khả năng –

+0

Đã cố gắng này, đã không làm việc.Đó phải là một cách tốt hơn so với sử dụng các truy vấn con tương ứng – Kash

2

này cần một chức năng OLAP để làm việc:

UPDATE Component SET Component.stage_id = Stage_Link.stage_id 
FROM Component 
JOIN (SELECT component_id, scanner_id, 
      ROW_NUMBER() OVER(PARTITION BY component_id 
           ORDER BY date_scanned DESC) rownum 
     FROM Scan) Scan 
    ON Scan.component_id = Component.component_id 
    AND Scan.rownum = 1 
JOIN Stage_Link 
    ON Stage_Link.scanner_id = Scan.scanner_id 
WHERE Component.stage_id IS NULL 

nào tạo ra một tập hợp kết quả của:

Component 
component_id stage_id 
======================== 
1    2 
2    1 
3    1 
4    null 
5    null 

(Tôi cũng có một tác SQL Fiddle example .)

+0

Cảm ơn bạn rất nhiều vì đã dành thời gian của bạn! truy vấn chạy trong hơn 1 giờ, nhưng vẫn không trả lại kết quả.Tôi thấy ý tưởng bạn cố thực hiện và tôi đồng ý với nó .. Tôi không hiểu tại sao cơ sở dữ liệu của tôi lại không chấp nhận nó :-P – mithilatw

+0

# winces # Thực ra, vấn đề của bạn là cơ sở dữ liệu của bạn _did_ chấp nhận nó - nó chỉ không chạy nhanh như nó có thể. Đó là _probably_ chạy truy xuất giá trị cho mỗi dòng. Đây không phải là một vấn đề khi nó nhỏ (như đối với dữ liệu thử nghiệm), nhưng rõ ràng là không quy mô tốt. SQL Server không hỗ trợ CTE trong câu lệnh 'UPDATE'? Bạn có thể cố gắng lấy ít nhất một phần với 'ROW_NUMBER()' vào một CTE, để nó chỉ được chạy một lần (đây có thể là tiết kiệm tốt nhất). Ngoài ra, kết xuất các kết quả của sub-select vào một bảng tạm thời, và chạy một cập nhật tương quan từ đó. –

+0

@ X-Zero: Tôi nghĩ bạn có nghĩa là truy vấn con tương quan thay vì CTE. SQL Server hỗ trợ cả hai, nhưng với các truy vấn con tương quan, như bạn đã đề cập, nó đánh giá cho mỗi hàng của Thành phần và do đó không được thiết lập chính xác mà sẽ giải thích tại sao phải mất một thời gian dài. – Kash

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