2009-02-09 29 views
17

Tôi muốn cung cấp điều kiện WHERE trên truy vấn bên trong bằng cách chỉ định innertable.id = outertable.id. Tuy nhiên, MySQL (5.0.45) báo cáo "cột không xác định 'outertable.id' trong 'where clause'". Đây có phải là loại truy vấn có thể không?Truy vấn con của MySQL có liên quan trong cú pháp JOIN

Truy vấn bên trong đang xoay vòng các hàng thành các cột bằng cách sử dụng GROUP BY. Điều này có thể hoàn toàn được thực hiện trong truy vấn bên ngoài, nhưng có thể sẽ phải trả thêm phí do các kết nối thêm. Ngoài ra, tôi có thể bỏ điều kiện WHERE trong truy vấn bên trong và thay vào đó chỉ định ON bên ngoài.id = innerquery.id, nhưng sau đó nó sẽ tìm nạp toàn bộ các hàng truy vấn bên trong để nối lại bên ngoài, đó là không hiệu quả.

SQL thực tế xuất hiện bên dưới:

select t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, tp.subject, tp.contents, a.PhoneNumber, a.Location, a.Extension, a.BusinessUnit, a.Department 
from swtickets t 
inner join swticketposts tp on t.ticketid = tp.ticketid 
inner join swusers u on t.userid = u.userid 
left join 
    (
    select 
    cfv.typeid, 
    min(case cfv.customfieldid when 1 then cfv.fieldvalue end) as 'PhoneNumber', 
    min(case cfv.customfieldid when 3 then cfv.fieldvalue end) as 'Location', 
    min(case cfv.customfieldid when 5 then cfv.fieldvalue end) as 'Extension', 
    min(case cfv.customfieldid when 8 then cfv.fieldvalue end) as 'BusinessUnit', 
    min(case cfv.customfieldid when 9 then cfv.fieldvalue end) as 'Department' 
    from swcustomfieldvalues cfv 
    where cfv.typeid = t.ticketid 
    group by cfv.typeid 
) as a on 1 = 1 
where t.ticketid = 2458; 
+2

Câu hỏi ban đầu của tôi là "Loại truy vấn này có thể không?" (liên quan đến MySQL 5.0). Thay đổi giản đồ hoặc sơ đồ trên mã ứng dụng nằm ngoài chủ đề câu hỏi. –

Trả lời

29

Câu trả lời cho câu hỏi của bạn là không, không thể tham chiếu tên tương quan như bạn đang làm. Bảng dẫn xuất được tạo bởi truy vấn bên trong của bạn trước khi truy vấn bên ngoài bắt đầu đánh giá các phép nối.Vì vậy, các tên tương quan như t, tpu không có sẵn cho truy vấn bên trong. Để giải quyết điều này, tôi khuyên bạn nên sử dụng cùng một giá trị nguyên không đổi trong truy vấn bên trong, và sau đó tham gia bảng dẫn xuất trong truy vấn bên ngoài bằng cách sử dụng điều kiện thực thay vì 1=1.

SELECT t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, 
    tp.subject, tp.contents, a.PhoneNumber, a.Location, a.Extension, 
    a.BusinessUnit, a.Department 
FROM swtickets t 
INNER JOIN swticketposts tp ON (t.ticketid = tp.ticketid) 
INNER JOIN swusers u ON (t.userid = u.userid) 
LEFT OUTER JOIN (
    SELECT cfv.typeid, 
    MIN(CASE cfv.customfieldid WHEN 1 THEN cfv.fieldvalue END) AS 'PhoneNumber', 
    MIN(CASE cfv.customfieldid WHEN 3 THEN cfv.fieldvalue END) AS 'Location', 
    MIN(CASE cfv.customfieldid WHEN 5 THEN cfv.fieldvalue END) AS 'Extension', 
    MIN(CASE cfv.customfieldid WHEN 8 THEN cfv.fieldvalue END) AS 'BusinessUnit', 
    MIN(CASE cfv.customfieldid WHEN 9 THEN cfv.fieldvalue END) AS 'Department' 
    FROM swcustomfieldvalues cfv 
    WHERE cfv.typeid = 2458 
    GROUP BY cfv.typeid 
) AS a ON (a.typeid = t.ticketid) 
WHERE t.ticketid = 2458; 
0

Đề nghị của tôi sẽ là những gì bạn loại trừ khả năng trên cơ sở hiệu quả. Ví dụ. bỏ qua mệnh đề where và sử dụng phép nối (theo t.ticketid = a.ticketid)

Bạn có thể chứng minh suy nghĩ của mình về sự kém hiệu quả của một số ví dụ cụ thể không? Tôi biết những gì bạn đang nói nhưng phương pháp bạn sử dụng mỗi hàng trong truy vấn bên ngoài đang được tham gia vào mỗi hàng trong truy vấn bên trong, do đó tùy thuộc vào kế hoạch thực hiện nó có thể không hiệu quả như bạn nghi ngờ?

0

Tôi tưởng tượng vấn đề là 'cfv.typeid = t.ticketid' sau đó? Suy nghĩ của tôi về điều đó sẽ là, trong khi MySQL hỗ trợ các truy vấn con tương quan, những gì bạn đang cố gắng làm dường như nó có thể thất bại trong một phép nối vì truy vấn 'bên trong' không thực sự là 'bên trong' phần còn lại của truy vấn giống như nó trong mệnh đề WHERE. Nhưng có vẻ như bạn chỉ có thể lấy mệnh đề where ra khỏi truy vấn con và tạo điều kiện tham gia của bạn trên a.typeid = t.ticketid.

+0

Xin lỗi, điều đó còn sót lại từ một biến thể truy vấn khác. Nó không liên quan gì đến lỗi thực tế đang được tạo ra, vì vậy tôi đã xóa nó khỏi câu hỏi trên. –

1

Tôi sẽ viết nó với nhiều lần tham gia. Khi bạn nói rằng nó "có thể sẽ phải trả thêm chi phí" mà nói với tôi rằng bạn đã không thử nghiệm nó để chắc chắn. Nếu bạn có chỉ mục phong nha thì các kết nối phải khá tầm thường.

Điều này cũng chỉ hiển thị một trong những cạm bẫy của mẫu thiết kế bảng "giữ mọi thứ" chung.

+1

Thật vậy. Thiết kế này được gọi là Entity-Attribute-Value. Nó phá vỡ bình thường theo nhiều cách, và nó rất khó sử dụng. –

+0

Sử dụng "WHERE cfv.typeid = 2458" trong truy vấn bên trong (cfv) gây ra việc quét bảng khó chịu trên cfv do thiếu chỉ mục đơn giản, tuy nhiên, bỏ điều kiện này làm cho mọi thứ trở nên tồi tệ hơn gây ra "Sử dụng tạm thời; "ngoài việc quét bảng bổ sung trên truy vấn có nguồn gốc. –

+0

Tôi không chắc chắn ý bạn là gì bởi "truy vấn bên trong". Sẽ có 5 kết nối bên trong mới, vì vậy có lẽ đó là ý của bạn. Tôi hy vọng rằng bảng CFV của bạn sẽ có chỉ mục về typeid. Tôi có thể có một chỉ số nhóm trên typeid và customfieldid theo thứ tự đó. –

2

Bạn đang sử dụng thiết kế Thuộc tính-Giá trị thuộc tính và cuối cùng không có cách nào để làm cho khả năng mở rộng này nếu bạn cố gắng tạo các tập kết quả thông thường. Đừng cố gắng làm điều này trong một truy vấn.

Thay vào đó, truy vấn bảng bình thường của bạn đầu tiên:

SELECT t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, 
    tp.subject, tp.contents 
FROM swtickets t 
INNER JOIN swticketposts tp ON (t.ticketid = tp.ticketid) 
INNER JOIN swusers u ON (t.userid = u.userid) 
WHERE t.ticketid = 2458; 

Sau đó truy vấn các lĩnh vực tùy chỉnh của bạn, với kết quả trên nhiều hàng của tập kết quả:

SELECT cfv.customfieldid, cfv.fieldvalue 
FROM swcustomfieldvalues cfv 
WHERE cfv.typeid = 2458; 

Bạn sẽ nhận được nhiều hàng trong tập hợp kết quả, một hàng cho mỗi trường tùy chỉnh:

+---------------+--------------+ 
| customfieldid | fieldvalue | 
+---------------+--------------+ 
|    1 | 415-555-1234 | 
|    3 | Third office | 
|    5 | 123   | 
|    8 | Support  | 
|    9 | Engineering | 
+---------------+--------------+ 

Sau đó, bạn cần phải viết đơn đăng ký mã để ánh xạ các trường kết quả thành các trường đối tượng ứng dụng, trong một vòng lặp.

Sử dụng bảng Thuộc tính-Giá trị thuộc tính theo cách này có thể mở rộng hơn cả về hiệu suất và bảo trì mã.

+0

Đề xuất này được thực hiện tương tự như truy vấn câu hỏi ban đầu (thay đổi "nơi cfv.typeid = t.ticketid" thành "nơi cfv.typeid = 2458"); thay vào đó, nó phụ thuộc vào mã bên ngoài cơ sở dữ liệu để thực hiện trục. –

+0

Vâng, chính xác. Trong trường hợp của EAV, không có cách nào để làm cho nó hiệu quả trong một truy vấn. Bạn nên làm trục trong mã ứng dụng. –

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