【问题标题】:SQL not exist issueSQL 不存在问题
【发布时间】:2011-05-15 20:44:56
【问题描述】:

处理查询中的不存在子句有点麻烦。

我有三张桌子:

用餐

no_meal integer
type_meal varchar(255)

消费

no_meal integer
designation varchar(255)
quantity integer

食物

designation varchar(255)
quantity integer
type varchar(255)

食物中的数量是储存的数量,消耗的数量是消耗的数量,所以它们会有所不同,因此自然内连接不会减少它。

  • 食物类型可以是“饮料”“肉”“鱼”等等。
  • 用餐类型可以是“早餐”“午餐”“晚餐”

我想要一个查询,告诉我在所有类型的膳食中消耗的饮料。

我一直在切换和测试代码,但无法正确处理。目前我正在尝试这个:

SELECT Consumed.designation
FROM Consumed
WHERE NOT EXISTS

(SELECT type_meal
 FROM Consumed, Food, Meal
 WHERE Consumed.designation = Food.designation
 AND Consumed.no_meal = Meal.no_meal
 AND type = 'Drink'
 ORDER BY Food.designation)

EXCEPT

(SELECT type_meal
 FROM Meal);

我到底怎么做对了?

感谢您的意见。

编辑

我将添加一些数据以使其更清晰。

食物

Steak   100    Meat
Water   200    Drink
Coca cola    300   Drink

用餐

0001     Breakfast
0002     Lunch
0003     Dinner

消费

0001     Water       50
0002     Steak       20
0001     Coca cola   20
0003     Water        5
0002     Water       15

现在,我想知道每顿饭都喝了哪种饮料,哪种只会给水。

希望我清除了一些关于这个问题的想法

【问题讨论】:

    标签: sql exists


    【解决方案1】:

    稍微扭曲一下你的想法,并以双重否定的方式思考......

    我想要 [...] 在所有类型的膳食中消耗的饮料。

    您想要所有没有膳食类型且该饮品不属于膳食类型的饮料:

    select distinct f.designation 
    from food f 
    where 
      type = 'Drink' and 
      not exists (
        select * 
        from meal m1
        where not exists (
          select *  
          from meal m2
          join consumed c on c.no_meal = m2.no_meal
          where 
            m1.no_meal = m2.no_meal and
            c.designation = f.designation
        )
      ) 
    

    这叫relational division

    【讨论】:

    • 对了!!!!这就是我想要的:) 但是嵌套的不存在让我很困惑:/ 感谢您的输入
    【解决方案2】:

    现在我明白你想要什么了...

    SELECT designation
    FROM Food
    WHERE designation IN (
        SELECT designation 
        FROM Consumed
        GROUP BY designation
        HAVING Count(DISTINCT no_meal) = (
            SELECT Count(*) FROM Meal
        )
    )
    WHERE type = 'Drink'
    

    【讨论】:

    • 此查询不需要数量。我只是把它放在那里,因为它不同并且不能使用自然内部连接。
    • 我需要的是每种膳食中消耗的“饮料”类型的食物名称。如果不使用食物,如何区分肉和鱼与饮料?
    【解决方案3】:

    我想要一个查询,告诉我在所有类型的膳食中消耗的饮料。

    您的编辑确实使事情变得清晰。请注意,如果 Designation, Typein Consumed 的组合不是唯一的,则以下查询将不起作用,但我猜它会是。

    SELECT  
        c.Designation
    FROM
        (SELECT  
             c.Designation
         FROM    
             Consumed c
         INNER JOIN 
             Meal m ON m.no_meal = c.no_meal
         GROUP BY
             c.Designation
         HAVING  
             COUNT(*) = (SELECT COUNT(*) FROM Meal)) c
    INNER JOIN 
        Food f ON f.Designation = c.Designation
    WHERE
        f.Type = 'Drink'                  
    

    【讨论】:

    • 猜我解释得不够清楚。我想要的不是每餐按类型消耗的饮料量我想知道是否有任何饮料在所有类型的膳食中消耗。我将在主页添加一些示例数据以便更好地解释
    • 编辑后,您原来的解释实际上是有道理的。我已经更改了声明。你能验证结果吗?
    • 我已经验证,它给出了一个空表:/我认为它必须使用 Roopesh Shenoy 给出的不存在子句来完成
    • @Martin,我在这里测试您的耐心,但我(再次)更改了查询。 join with food 应该放在 group by 语句之外。
    • 别担心。然而,它仍然是一张空桌子
    【解决方案4】:
    select *
    from food f inner join
         consumed c_1 on c_1.designation = f.designation
    where type='Drink' and
    not exists -- to filter out drinks that are not a part of all the meals
    (select 1 
    from consumed c_2 inner join
         meal m_1 on m_1.no_meal = c_2.no_meal
    where c_1.no_meal = c2.no_meal and
          c_1.designation = c2.designation and
     not exists (select 1 
                   from meal m_2
                  where m_1.no_meal = m_2.no_meal))
    

    【讨论】:

    • 我运行它并在不存在之前添加了一个“和”,给出的结果与 select*from food where type='Drink' 似乎过滤器不起作用
    • 我认为这也是不存在的,但我似乎无法正确理解。过滤器无法正常工作
    • 编辑 - 添加了 and。让我检查一下查询的其余部分。
    • 不幸的是,它仍然给出了同样的结果。我很好奇如何使它与不存在一起工作,因为卢塞罗的回答有点作弊,并且仅在不存在的情况下才适用于这个问题,这是解决它的更一般的方法
    • 我明天再试一次......
    【解决方案5】:

    我想要一个查询,告诉我在所有类型的膳食中消耗的饮料。

    这是您建议的模型结构和插入:

    USE SqlTests
    GO
    
    CREATE TABLE Meal (
        no_meal int
        , type_meal nvarchar(255)
    )
    GO
    
    insert into Meal (no_meal, type_meal)
        values (1, N'Breakfast')
    GO
    insert into Meal (no_meal, type_meal)
        values(2, N'Lunch')
    GO
    insert into Meal (no_meal, type_meal)
        values(3, N'Dinner')
    GO
    
    CREATE TABLE Consumed (
        no_meal int
        , designation nvarchar(255)
        , quantity int
    )
    GO
    
    insert into Consumed (no_meal, designation, quantity)
        values (1, N'Water', 50)
    GO
    insert into Consumed (no_meal, designation, quantity)
        values (2, N'Steak', 20)
    GO
    insert into Consumed (no_meal, designation, quantity)
        values (1, N'Coca cola', 20)
    GO
    insert into Consumed (no_meal, designation, quantity)
        values(3, N'Water', 5)
    GO
    insert into Consumed (no_meal, designation, quantity)
        values(2, N'Water', 15)
    GO
    
    CREATE TABLE Food (
        designation nvarchar(255)
        , quantity int
        , [type] nvarchar(255)
    )
    GO
    
    insert into Food (designation, quantity, [type])
        values (N'Water', 200, N'Drink')
    GO
    insert into Food (designation, quantity, [type])
        values (N'Steak', 100, N'Meat')
    GO
    insert into Food (designation, quantity, [type])
        values (N'Coca cola', 200, N'Drink')
    GO
    

    然后,选择建议的SELECT

    select c.designation
        from Consumed c
            inner join Meal m on m.no_meal = c.no_meal
            inner join Food f on f.designation = c.designation and f.[type] LIKE N'Drink'
        group by c.designation 
            having COUNT(c.designation) = (select COUNT(type_meal) from Meal)
    

    返回(至少在我的数据库引擎上(SQL Server Express 2005)

    Water

    我的信息数据正确吗?

    【讨论】:

    • 这将给我按餐食类型订购的每一种饮料,而不是在所有类型的餐食中消耗的每一种饮料都会返回:早餐水早餐可乐午餐水晚餐水从这里开始,我希望它只给我每种膳食类型中出现的饮料。在这个例子中,水。够清楚吗?不知道我能解释多少更好:S
    • 伙计,这个答案编辑器太糟糕了:S 我用段落写的,但他们把它们删掉了:/
    • @Martin:感谢您的解释。现在很清楚了。您必须考虑到许多 SO 用户不是以英语为母语的人,因此某些微妙之处对于说英语的人来说可能是显而易见的,但对于非英语人士来说并非如此,尽管人们可能会说和理解 Ensligh。感谢你的理解。我将获取您的数据样本并在我的测试数据库上进行尝试。 =)
    • 没问题威尔,我也不是以英语为母语的人:) 无论如何,你可以拿我在首页提供的数据并从那里开始,目标是让它送水。跨度>
    • @Martin:在测试后编辑了我的答案。我离解决方案不远了。请参阅提供的代码示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多