【问题标题】:Rewriting simple query using EXISTS, IN, ALL, ANY operatorsRewriting simple query using EXISTS, IN, ALL, ANY operators
【发布时间】:2022-12-02 03:45:26
【问题描述】:

I have the following tables: Ships (Name is PK)

Name Class Launching_year
Kongo Kongo 1912
Haruna Kongo 1913
Evstafi Evstafi 1906

Consequences ((Ship, Battle) is UK, ship is FK to Ships table)

Ship Battle Result
Kongo Midway Battle unharmed
Haruna Guadalcanal Campaign unharmed
Evstafi Battle from Cape Sarych unharmed

I have to find the name of those ships that participated in the battles in which ships from the Kongo class participated. I have to use a subquery and EXISTS, IN, ALL or ANY operators and I can't use aggregate functions (COUNT, SUM, MAX, MIN, etc). I'm using Oracle DB.

I can find the answer with the following query(version1):

SELECT s.name
FROM ships s JOIN consequences c ON (s.name = c.ship)
WHERE s.class = 'Kongo' AND c.battle IS NOT NULL;

Returning: Kongo, Haruna

I managed to rewrite the code in the following way(version2):

SELECT name
FROM ships
WHERE name IN (SELECT s.name
               FROM ships s JOIN consequences c ON (s.name = c.ship)
               WHERE s.class = 'Kongo' AND c.battle IS NOT NULL)

The query returns the same results. I'm not satisfied with this solution, because the only thing I did was placing version 1 as a subquery in version 2, where once again I'm selecting the name of the ships.

I was wondering if there are other more elegant solutions to this problem.

【问题讨论】:

  • I'd use EXISTS here. (Well, I'd rather keep the JOIN.)
  • I tried using EXISTS this way: SELECT name FROM ships WHERE EXISTS (SELECT c.battle FROM ships s JOIN consequences c ON (s.name = c.ship) WHERE s.class = 'Kongo' AND c.battle IS NOT NULL ) When I run the code it returns Kongo, Haruna, Evstafi instead of Kongo, Haruna.
  • No need for a JOIN in the subquery, Instead havecorrelated subquery, i.e. include a condition referencing the outer query.
  • Like this: SELECT name FROM ships WHERE EXISTS (SELECT c.ship FROM consequences c WHERE s.class = 'Kongo') ? Let's say I insert ('Haruna1', 'Kongo', 1914) into Ships and ('Haruna1', NULL, 'unharmed') into consequences. In this case Haruna1 has no battles so it should not be returned by the query, but it will. I tried this way, but Haruna1 is still returned: SELECT name FROM ships s WHERE EXISTS (SELECT ship FROM consequences c WHERE s.class = 'Kongo' AND c.battle IS NOT NULL ) . What should I do?

标签: sql oracle operators


【解决方案1】:

With your sample data:

WITH
    ships AS
        (
            Select 'Kongo'   "NAME", 'Kongo'   "CLASS", 1912 "LAUNCH_YEAR" From Dual Union All
            Select 'Haruna'  "NAME", 'Kongo'   "CLASS", 1913 "LAUNCH_YEAR" From Dual Union All
            Select 'Evstafi' "NAME", 'Evstafi' "CLASS", 1906 "LAUNCH_YEAR" From Dual 
        ),
    consequences AS
        (
            Select 'Kongo'   "SHIP", 'Midway Battle'            "BATTLE", 'unharmed' "RESULT" From Dual Union All
            Select 'Haruna'  "SHIP", 'Guadalcanal Campaign'     "BATTLE", 'unharmed' "RESULT" From Dual Union All
            Select 'Evstafi' "SHIP", 'Battle from Cape Sarych'  "BATTLE", 'unharmed' "RESULT" From Dual 
        )

... using EXISTS (subquery)

Select  c.SHIP
From    consequences c
Where   EXISTS (Select NAME From ships where NAME = c.SHIP And CLASS = 'Kongo')

--  SHIP  
--  -------
--  Kongo   
--  Haruna

... using IN (subquery)

Select  s.NAME 
From    ships s
Where   s.CLASS = 'Kongo' And
        s.NAME IN(Select SHIP From consequences where SHIP = s.NAME)

--  NAME  
--  -------
--  Kongo   
--  Haruna 

... using ANY (subquery)

Select  c.SHIP
From    consequences c
Where   c.SHIP = ANY (Select NAME From ships where NAME = c.SHIP And CLASS = 'Kongo')    

--  SHIP  
--  -------
--  Kongo   
--  Haruna 

【讨论】:

    猜你喜欢
    • 2013-07-07
    • 2022-09-27
    • 2022-12-02
    • 1970-01-01
    • 2019-08-29
    • 2014-04-06
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多