oracle 仅返回两个表中完全匹配的数据

nr7wwzry  于 2023-04-05  发布在  Oracle
关注(0)|答案(2)|浏览(143)
SELECT
    b.ID
FROM
    PLACE b
    JOIN ART_TO_PLACE a ON b.ALIAS = a.PLACE_ALIAS
    JOIN ART_TO_UNIT t ON t.MATL_TU_IDENT = :AUNITIDENT
WHERE
    (
        (a.GRP = t.GRP) --All GRPs must match, not just one
    )
FETCH NEXT 1 ROWS ONLY

如果有一些a.GRP在ART_TO_UNIT中没有匹配项,或者如果有一些t.GRP在ART_TO_PLACE中没有匹配项,则不为其返回B.ID。查找下一个PLACE条目。
如何在没有动态SQL的情况下做到这一点?

更新

不好意思,这本来应该在问题里的,现在不删掉上面的部分了,因为已经有两个人回复了。
这里是MS SQL Server的最小可重复示例,因为我没有Oracle作为Playground:

CREATE TABLE WorkplaceCapabilities(
    ID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
    WorkplaceID int NOT NULL,
    AllowedType nvarchar(50) NOT NULL
)

INSERT INTO WorkplaceCapabilities (WorkplaceID, AllowedType) VALUES (1, 'Wood');

INSERT INTO WorkplaceCapabilities (WorkplaceID, AllowedType) VALUES (2, 'Gas');
INSERT INTO WorkplaceCapabilities (WorkplaceID, AllowedType) VALUES (2, 'Oil');

INSERT INTO WorkplaceCapabilities (WorkplaceID, AllowedType) VALUES (3, 'Steel');
INSERT INTO WorkplaceCapabilities (WorkplaceID, AllowedType) VALUES (3, 'Wood');

INSERT INTO WorkplaceCapabilities (WorkplaceID, AllowedType) VALUES (4, 'Gas');
INSERT INTO WorkplaceCapabilities (WorkplaceID, AllowedType) VALUES (4, 'Plastic');
INSERT INTO WorkplaceCapabilities (WorkplaceID, AllowedType) VALUES (4, 'Steel');

CREATE TABLE TransportUnitContents(
    ID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
    UnitID int NOT NULL,
    ContainedMaterial nvarchar(50) NOT NULL
)

INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (152, 'Wood');

INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (25, 'Oil');
INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (25, 'Gas');

INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (122, 'Wood');
INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (122, 'Steel');

INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (13, 'Gas');
INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (13, 'Steel');
INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (13, 'Plastic');

INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (99, 'Gas');

INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (111, 'Steel');
INSERT INTO TransportUnitContents (UnitID, ContainedMaterial) VALUES (111, 'Plastic');

现在我想有这样一个SQL查询,将返回

  • 用于运输单元152 -工作场所1
  • 用于运输单元25 -工作场所2
  • 用于运输单元122 -工作场所3
  • 用于运输单元13 -工作场所4
  • 99 ----无工作场所
  • 用于运输单元111 -无工作场所
nhhxz33t

nhhxz33t1#

如果没有样本数据,很难回答,但看起来你想在ART_TO_PLACEART_TO_UNIT之间使用FULL OUTER JOIN,然后聚合并使用HAVING子句来检查没有行被OUTER JOIN ed(相反,所有行都匹配):

SELECT b.ID
FROM   PLACE b
       INNER JOIN (
         ART_TO_PLACE a
         FULL OUTER JOIN ART_TO_UNIT t
         ON     t.MATL_TU_IDENT = :AUNITIDENT
            AND a.GRP = t.GRP
       )
       ON b.ALIAS = a.PLACE_ALIAS
GROUP BY b.id
HAVING COUNT(CASE WHEN a.grp IS NULL THEN 1 END) = 0
AND    COUNT(CASE WHEN t.grp IS NULL THEN 1 END) = 0
ORDER BY b.id
FETCH NEXT 1 ROWS ONLY

或者可能是:

SELECT b.ID
FROM   PLACE b
       INNER JOIN (
         SELECT a.place_alias
         FROM   ART_TO_PLACE a
                FULL OUTER JOIN ART_TO_UNIT t
                ON     t.MATL_TU_IDENT = :AUNITIDENT
                   AND a.GRP = t.GRP
         GROUP BY a.place_alias
         HAVING COUNT(CASE WHEN a.grp IS NULL THEN 1 END) = 0
         AND    COUNT(CASE WHEN t.grp IS NULL THEN 1 END) = 0
       ) b
       ON b.ALIAS = a.PLACE_ALIAS
ORDER BY b.id
FETCH NEXT 1 ROWS ONLY

样本数据更新:

选项1:使用集合

定义集合数据类型:

CREATE TYPE string_list IS TABLE OF VARCHAR2(50);

然后,您可以将两个表的值收集到集合中,并在相同的集合值上进行连接:

SELECT workplaceid, unitid
FROM   ( SELECT workplaceid,
                CAST(COLLECT(allowedtype) AS string_list) AS allowedtypes
         FROM   WorkplaceCapabilities
         GROUP BY Workplaceid
       ) w
       INNER JOIN (
         SELECT unitid,
                CAST(COLLECT(containedmaterial) AS string_list) AS containedmaterials
         FROM   TransportUnitContents
         GROUP BY unitid
       ) t
       ON w.allowedtypes = t.containedmaterials;
选项2:比较计数

统计每个表中每个组的类型/材料数量,然后进行连接,并检查连接后的匹配数量是否相同:

SELECT workplaceid, unitid
FROM   ( SELECT wc.*,
                COUNT(allowedtype) OVER (PARTITION BY workplaceid) AS num_allowedtypes
         FROM   WorkplaceCapabilities wc
       ) w
       INNER JOIN (
         SELECT tuc.*,
                COUNT(containedmaterial) OVER (PARTITION BY unitid) AS num_containedmaterials
         FROM   TransportUnitContents tuc
       ) t
       ON (w.allowedtype = t.containedmaterial AND w.num_allowedtypes = t.num_containedmaterials)
GROUP BY
       w.workplaceid, t.unitid
HAVING COUNT(*) = MAX(w.num_allowedtypes)

对于示例数据,两个选项都将输出:
| 工作场所ID|UNITID|
| --------------|--------------|
| 1|一百五十二|
| 第二章|二十五|
| 三|一百二十二|
| 四|十三|
fiddle

6bc51xsx

6bc51xsx2#

如果我对你的问题理解正确的话,你可以像这样使用嵌套的exists条件:

select *
from PLACE b
where
    exists (
        select 1
        from ART_TO_PLACE a
        where b.ALIAS = a.PLACE_ALIAS
        and exists (
                select 1
                from ART_TO_UNIT t
                where a.GRP = t.GRP
                and t.MATL_TU_IDENT = AUNITIDENT
            )
    )

相关问题