SQL: tham gia: tìm tất cả các đối tượng thỏa mãn một số yêu cầu


8

Tôi có một bảng chứa danh sách các đối tượng và những yêu cầu mà chúng đáp ứng. Sau đó, tôi có một bảng chứa danh sách các nhiệm vụ và yêu cầu mà một đối tượng phải thực hiện để có thể thực hiện nhiệm vụ. Tôi muốn truy vấn: được giao một nhiệm vụ, cho tôi xem tất cả các đối tượng có thể thực hiện nhiệm vụ đó và đưa ra một đối tượng, cho tôi thấy tất cả các nhiệm vụ mà đối tượng có thể thực hiện:

Thí dụ:

bảng task_Vq

tasks   |    reqs
-----------------
taskA   |    req1
taskA   |    req2
taskA   |    req3
taskB   |    req4
taskB   |    req5
taskB   |    req6

Vì vậy, bảng này nói rằng để thực hiện taskA, các yêu cầu req1, req2 và req3 là cần thiết.

bảng obj numqs

object  |   reqs
----------------
obj1    |   req3
obj1    |   req4
obj2    |   req1
obj2    |   req2
obj2    |   req3
obj2    |   req4

Vì vậy, tôi có thể đặt câu hỏi: những đối tượng nào có thể thực hiện taskA? Câu trả lời chỉ nên là một hàng:

tasks   |   objects
-------------------
taskA   |   object2

bởi vì obj2 là cái duy nhất đáp ứng các yêu cầu req1, req2, req3. Câu hỏi khác nhau: những đối tượng nào có thể thực hiện taskB? Câu trả lời là không, bởi vì không có đối tượng nào có yêu cầu req4, req5, req6. Truy vấn phải được xử lý logic trong đó một tác vụ có thể được thực hiện bởi nhiều đối tượng bằng cách trả về nhiều hàng.

Câu hỏi là: truy vấn này làm gì?

Vấn đề của tôi là tôi đã tìm được một truy vấn như vậy, nhưng dường như nó quá phức tạp. Về cơ bản, truy vấn thực hiện: A) bảng tác vụ tham gia bên trong với bảng obj numqs, nhóm theo nhiệm vụ và objs và đếm các yêu cầu riêng biệt, B) chọn các nhiệm vụ, đếm (phân biệt (reqs)) từ nhóm nhiệm vụ theo nhiệm vụ, C) tham gia bên trong A và B trên cả nhiệm vụ và số đếm (riêng biệt (reqs)).

Chắc chắn có một cách dễ dàng hơn để thực hiện truy vấn này, phải không?

Tôi đang dán bên dưới mã SQL để tạo các bảng và truy vấn của tôi.

create table task_reqs (task varchar, req varchar);
create table obj_reqs (object varchar, req varchar);
insert into task_reqs values ('taskA', 'req1');
insert into task_reqs values ('taskA', 'req2');
insert into task_reqs values ('taskA', 'req3');
insert into task_reqs values ('taskB', 'req4');
insert into task_reqs values ('taskB', 'req5');
insert into task_reqs values ('taskB', 'req6');
insert into obj_reqs values ('obj1','req1');
insert into obj_reqs values ('obj1','req3');
insert into obj_reqs values ('obj2','req1');
insert into obj_reqs values ('obj2','req2');
insert into obj_reqs values ('obj2','req3');
insert into obj_reqs values ('obj2','req4');

và truy vấn của tôi:

select t.task,t.object,n.n_reqs
from (
    select task,object,count(distinct(obj_reqs.req)) as n_reqs
    from task_reqs
    inner join obj_reqs on task_reqs.req=obj_reqs.req
    group by task,object
) t
inner join (
    select task,count(distinct(req)) as n_reqs
    from task_reqs
    group by task
) n
on n.n_reqs=t.n_reqs and n.task=t.task;

Trả về:

 task  | object | n_reqs 
-------+--------+--------
 taskA | obj2   |      3

Chắc chắn có một cách đơn giản hơn.


Không liên quan đến vấn đề của bạn, nhưng: distinctkhông một hàm. Đóng một cột được sử dụng cho distinctdấu ngoặc đơn sẽ không thay đổi bất cứ điều gì và là vô ích. count(distinct (a))giống nhưcount(distinct a)
a_horse_with_no_name

Câu trả lời:


1

Đây là một cách đơn giản hơn có thể:

select t.task, o.object, count(t.req) n_reqs
  from task_reqs t left join obj_reqs o on t.req = o.req
  group by t.task, o.object
  having o.object is not null and count(t.req) = (select count(req) from task_reqs where 
  task = t.task)

Bản giới thiệu


Đây là giải pháp ưa thích của tôi. Bạn có thể thêm một ví dụ về SQL, như những người trả lời khác đã làm không?
chúc mừng

Chắc chắn rồi. Bây giờ nó được thêm vào.
rad

2

Bạn có thể làm điều đó với sự tham gia chéo của các bảng:

select t.task, o.object, count(distinct t.req) n_reqs 
from task_reqs t cross join obj_reqs o
where t.task = 'taskA'
group by t.task, o.object
having count(distinct t.req) = count(case when t.req = o.req then 1 end)

Xem bản demo .
Các kết quả:

| task  | object | n_reqs |
| ----- | ------ | ------ |
| taskA | obj2   | 3      |

Không tham gia chéo thực sự xấu?
cheif

Đối với 2 bàn lớn thì thật tệ.
forpas

1

Truy vấn của bạn có vẻ tốt. Tôi tin rằng điều này sẽ trở nên phức tạp cho dù bạn theo đuổi nó như thế nào vì tiêu chí tham gia và / hoặc nơi mà các vị từ sẽ phụ thuộc vào cả hai reqvà số lượngreq kết hợp.

Các chức năng của cửa sổ có thể cắt giảm thời gian xử lý tại đây vì bạn có thể loại bỏ việc quét bảng khỏi truy vấn ban đầu.

SELECT DISTINCT task, object
FROM
  (
    SELECT task, 
      object, 
      COUNT(*) OVER (PARTITION BY task, object) matchCount,
      trqs.reqCount
    FROM (SELECT task, req, count(*) OVER (PARTITION BY task) as reqcount FROM task_reqs) trqs
      INNER JOIN obj_reqs orqs
        ON trqs.req = orqs.req
   ) taskreqcounter
WHERE matchCount = reqCount 

Nếu bạn có một chỉ mục trên obj_reqs.reqtôi nghĩ bạn cũng sẽ thấy truy vấn này khá nhanh. Nếu bạn chỉ quan tâm đến một nhiệm vụ cụ thể thì bạn có thể thêm nó vào WHEREmệnh đề trong truy vấn con nhất bên trong (trqs ).

SQLFiddle tại đây

Đảo ngược logic này hoạt động cho câu hỏi 2

SELECT DISTINCT task, object
FROM
  (
    SELECT task, 
      object, 
      COUNT(*) OVER (PARTITION BY task, object) matchCount,
      orqs.reqCount
    FROM (SELECT object, req, count(*) OVER (PARTITION BY object) as reqcount FROM obj_reqs) orqs
      INNER JOIN task_reqs trqs
        ON orqs.req = trqs.req
   ) taskreqcounter
WHERE matchCount = reqCount

SQLFiddle tại đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.