2013-05-01 26 views
33

Sử dụng sơ đồ sau:Sử dụng nhóm bằng và có khoản

Supplier (sid, name, status, city) 
Part (pid, name, color, weight, city) 
Project (jid, name, city) 
Supplies (sid, pid, jid**, quantity) 
  1. số nhà cung cấp Nhận và tên các nhà cung cấp của các bộ phận cung cấp cho ít nhất hai dự án khác nhau.

  2. Nhận số và tên nhà cung cấp cho các nhà cung cấp cùng một bộ phận với ít nhất hai dự án khác nhau.

Đây là những câu trả lời của tôi:

1.

SELECT s.sid, s.name 
FROM Supplier s, Supplies su, Project pr 
WHERE s.sid = su.sid AND su.jid = pr.jid 
GROUP BY s.sid, s.name 
HAVING COUNT (DISTINCT pr.jid) >= 2 

2.

SELECT s.sid, s.name 
FROM Suppliers s, Supplies su, Project pr, Part p 
WHERE s.sid = su.sid AND su.pid = p.pid AND su.jid = pr.jid 
GROUP BY s.sid, s.name 
HAVING COUNT (DISTINCT pr.jid)>=2 

bất cứ ai có thể khẳng định nếu tôi viết điều này một cách chính xác? Tôi hơi bối rối về cách điều khoản của Nhóm theo và Có hoạt động

Trả lời

0

Loại cơ sở dữ liệu sql nào đang sử dụng (MSSQL, Oracle, v.v ...)? Tôi tin rằng những gì bạn đã viết là chính xác.

Bạn cũng có thể viết các truy vấn đầu tiên như thế này:

SELECT s.sid, s.name 
FROM Supplier s 
WHERE (SELECT COUNT(DISTINCT pr.jid) 
     FROM Supplies su, Projects pr 
     WHERE su.sid = s.sid 
      AND pr.jid = su.jid) >= 2 

Nó dễ đọc hơn một chút, và ít tâm-uốn hơn là cố gắng làm điều đó với GROUP BY. Hiệu suất có thể khác nhau mặc dù.

+0

Bạn đang thiếu một 'khoản FROM' ... – plalx

+0

có, sử dụng Ms SQL. Cảm ơn vì sự trả lời. Đối với nhiệm vụ, chúng tôi giả sử sử dụng mệnh đề GROUP BY nên tôi không chắc chắn việc viết lại nó sẽ giúp tôi. Tôi đồng ý rằng GROUP BY là khó làm theo mặc dù! – user2341124

+0

@plalx thanks fixed.So đây là bài tập về nhà? – cbp

1

Trước hết, bạn nên sử dụng cú pháp JOIN thay vì FROM table1, table2 và bạn luôn phải giới hạn nhóm thành các trường nhỏ tùy ý.

Altought tôi đã không kiểm tra, truy vấn đầu tiên của bạn có vẻ tốt với tôi, nhưng có thể được viết lại như sau:

SELECT s.sid, s.name 
FROM 
    Supplier s 
    INNER JOIN (
     SELECT su.sid 
     FROM Supplies su 
     GROUP BY su.sid 
     HAVING COUNT(DISTINCT su.jid) > 1 
    ) g 
     ON g.sid = s.sid 

Hoặc đơn giản như:

SELECT sid, name 
FROM Supplier s 
WHERE (
    SELECT COUNT(DISTINCT su.jid) 
    FROM Supplies su 
    WHERE su.sid = s.sid 
) > 1 

Tuy nhiên, truy vấn thứ hai của bạn có vẻ sai với tôi, bởi vì bạn cũng nên GROUP BY pid.

SELECT s.sid, s.name 
    FROM 
     Supplier s 
     INNER JOIN (
      SELECT su.sid 
      FROM Supplies su 
      GROUP BY su.sid, su.pid 
      HAVING COUNT(DISTINCT su.jid) > 1 
     ) g 
      ON g.sid = s.sid 

Như bạn có thể nhận thấy trong các truy vấn trên, tôi đã sử dụng cú pháp INNER JOIN để thực hiện việc lọc, tuy nhiên nó cũng có thể được viết như sau:

SELECT s.sid, s.name 
FROM Supplier s 
WHERE (
    SELECT COUNT(DISTINCT su.jid) 
    FROM Supplies su 
    WHERE su.sid = s.sid 
    GROUP BY su.sid, su.pid 
) > 1 
+0

Cảm ơn bạn! Chúng tôi chưa học được sự tham gia bên trong nên tôi không biết cách sử dụng nó. Tuy nhiên, tôi sẽ thêm câu lệnh GROUP BY pid vào truy vấn thứ hai. – user2341124

+0

@ user2341124, Rất vui được tôi có thể trợ giúp. Vui lòng xem xét đánh dấu câu trả lời là được chấp nhận. Cảm ơn. – plalx

+0

Có vẻ như giảng viên của bạn hơi lạc hậu. Bạn đã sử dụng 'inner joins', bạn chỉ sử dụng cú pháp cũ hơn. –

82

Ngữ nghĩa của Có

Để hiểu rõ hơn về việc có, bạn cần xem nó từ quan điểm lý thuyết.

Một nhóm theo là truy vấn lấy bảng và tóm tắt nó thành bảng khác. Bạn tóm tắt bảng gốc bằng cách nhóm bảng gốc thành các tập con (dựa trên các thuộc tính mà bạn chỉ định trong nhóm). Mỗi nhóm trong số này sẽ mang lại một tuple.

Các chỉ đơn giản là tương đương với một mệnh đề WHERE sau nhóm bằng cách đã thực hiện và trước khi chọn phần của truy vấn được tính.

phép nói rằng truy vấn của bạn là:

select a, b, count(*) 
from Table 
where c > 100 
group by a, b 
having count(*) > 10; 

Việc đánh giá của truy vấn này có thể được coi là các bước sau:

  1. Thực hiện các đề WHERE, loại bỏ hàng không đáp ứng nó.
  2. Nhóm bảng thành các tập con dựa trên các giá trị của a và b (mỗi bộ trong mỗi tập con có cùng giá trị a và b).
  3. Loại bỏ các tập hợp con không đáp ứng điều kiện HAVING
  4. Xử lý từng tập hợp con xuất các giá trị như được chỉ ra trong phần CHỌN của truy vấn. Điều này tạo ra một bộ dữ liệu đầu ra cho mỗi tập hợp con còn lại sau bước 3.

Bạn có thể mở rộng truy vấn phức tạp để trả về bảng (một sản phẩm chéo, tham gia, UNION, v.v.) .

Thực tế, syntactic sugar và không mở rộng sức mạnh của SQL. Bất kỳ truy vấn cụ thể:

SELECT list 
FROM table 
GROUP BY attrList 
HAVING condition; 

thể được viết lại như sau:

SELECT list from (
    SELECT listatt 
    FROM table 
    GROUP BY attrList) as Name 
WHERE condition; 

Các listatt là một danh sách bao gồm GROUP BY thuộc tính và các biểu thức được sử dụng trong danh sách và điều kiện. Nó có thể là cần thiết để đặt tên một số biểu thức trong danh sách này (với AS). Ví dụ, truy vấn ví dụ trên có thể được viết lại như sau:

select a, b, count 
from (select a, b, count(*) as count 
     from Table 
     where c > 100 
     group by a, b) as someName 
where count > 10; 

Các giải pháp bạn cần

giải pháp của bạn có vẻ là đúng:

SELECT s.sid, s.name 
FROM Supplier s, Supplies su, Project pr 
WHERE s.sid = su.sid AND su.jid = pr.jid 
GROUP BY s.sid, s.name 
HAVING COUNT (DISTINCT pr.jid) >= 2 

Bạn tham gia ba bảng, sau đó sử dụng sid như một thuộc tính nhóm (sname phụ thuộc vào chức năng của nó, do đó nó không ảnh hưởng đến số lượng nhóm, nhưng bạn phải bao gồm nó, nếu không nó không thể là một phần của phần chọn của câu lệnh). Sau đó, bạn đang loại bỏ những thứ không thỏa mãn điều kiện của bạn: thỏa mãn pr.jid is >= 2, điều bạn muốn ban đầu.

giải pháp tốt nhất cho vấn đề của bạn

Cá nhân tôi muốn có một giải pháp đơn giản sạch:

  1. Bạn cần phải nhóm chỉ bởi Vật tư (sid, pid, jid **, số lượng) để tìm sid của những người cung cấp ít nhất cho hai dự án.
  2. Sau đó, hãy tham gia vào bảng Nhà cung cấp để nhận được nhà cung cấp giống nhau.

SELECT sid, sname from 
    (SELECT sid from supplies 
    GROUP BY sid, pid 
    HAVING count(DISTINCT jid) >= 2 
    ) AS T1 
NATURAL JOIN 
Supliers; 

Nó cũng sẽ nhanh hơn để thực hiện, bởi vì tham gia chỉ được thực hiện khi cần thiết, không phải tất cả các lần.

--dmg

+0

'CHỌN sid từ số lượng'? Bạn đã thấy cái bàn đó ở đâu? – plalx

+0

Chúng ta có thể thực hiện 'SELECT count (sid), sname FROM GROUP GROUP BY tên HAVING name = 'Alice''? – Jus12

+0

Có. name là thuộc tính của kết quả của nhóm. Nhưng nó sẽ là tốt hơn để làm điều đó trong mệnh đề where (trước khi nhóm của). – dmg

0

số nhà cung cấp 1.Get và tên các nhà cung cấp của các bộ phận cung cấp cho ít nhất hai dự án khác nhau.

SELECT S.SID, S.NAME 
FROM SUPPLIES SP 
JOIN SUPPLIER S 
ON SP.SID = S.SID 
WHERE PID IN 
(SELECT PID FROM SUPPPLIES GROUP BY PID, JID HAVING COUNT(*) >= 2) 

Tôi không slear về câu hỏi thứ hai của bạn

3

Bởi vì chúng ta không thể sử dụng mệnh đề WHERE với chức năng tổng hợp như count(), min(), sum() vv để có khoản đã tồn tại để khắc phục vấn đề này trong sql. xem ví dụ để có khoản đi qua liên kết này

http://www.sqlfundamental.com/having-clause.php

+4

có một liên kết khác? Điều đó đã xảy ra: ( – mikermcneil

+0

http://www.techonthenet.com/sql/having.php – showdev

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