从3个表中选择(一对多,多对一关系)

时间:2015-02-02 12:58:03

标签: sql sql-server

我有3张桌子: 食谱(1 --- *)Ingridients(* --- 1)产品。我需要获取包含给定列表中的产品的食谱或不在列表中但具有特定标志集的产品。我在产品表(bool)中有一个标志。所以where子句如下:

WHERE Product.Caption IN ('A', 'B', 'C') OR (Product.Caption NOT IN ('A', 'B', 'C') AND Product.Flag=TRUE)

重要的是:我不需要包含列表中产品的配方,也包含其他产品(不在列表中,标志为false)。

Bellow是MSSQL的示例数据库转储:

USE [master]
IF EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = N'movedb') ALTER DATABASE [movedb] SET SINGLE_USER With ROLLBACK IMMEDIATE
IF EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = N'movedb') DROP DATABASE [movedb]
IF NOT EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = N'movedb') CREATE DATABASE [movedb]
USE [movedb]

--
-- Table structure for table 'Ingridients'
--

IF object_id(N'Ingridients', 'U') IS NOT NULL DROP TABLE [Ingridients]

CREATE TABLE [Ingridients] (
  [Id] INT NOT NULL IDENTITY, 
  [Quantity] INT DEFAULT 0, 
  [IdProduct] INT DEFAULT 0, 
  [IdRecipe] INT DEFAULT 0, 
  PRIMARY KEY ([Id])
)

SET IDENTITY_INSERT [Ingridients] ON
GO

--
-- Dumping data for table 'Ingridients'
--

INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (1, 0, 1, 2)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (2, 0, 3, 2)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (3, 0, 4, 2)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (4, 0, 6, 2)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (5, 0, 2, 3)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (6, 0, 4, 3)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (7, 0, 8, 3)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (8, 0, 1, 4)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (9, 0, 6, 4)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (10, 0, 5, 4)
-- 10 records

SET IDENTITY_INSERT [Ingridients] OFF
GO

--
-- Table structure for table 'Products'
--

IF object_id(N'Products', 'U') IS NOT NULL DROP TABLE [Products]

CREATE TABLE [Products] (
  [Id] INT NOT NULL IDENTITY, 
  [Caption] NVARCHAR(255), 
  [EasyToFind] BIT DEFAULT 0, 
  PRIMARY KEY ([Id])
)

SET IDENTITY_INSERT [Products] ON
GO

--
-- Dumping data for table 'Products'
--

INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (1, N'ProductA', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (2, N'ProductB', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (3, N'ProductC', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (4, N'ProductD', -1)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (5, N'ProductE', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (6, N'ProductF', -1)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (7, N'ProductG', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (8, N'ProductH', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (9, N'ProductI', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (10, N'ProductJ', 0)
-- 10 records

SET IDENTITY_INSERT [Products] OFF
GO

--
-- Table structure for table 'Recipes'
--

IF object_id(N'Recipes', 'U') IS NOT NULL DROP TABLE [Recipes]

CREATE TABLE [Recipes] (
  [Id] INT NOT NULL IDENTITY, 
  [Caption] NVARCHAR(255), 
  PRIMARY KEY ([Id])
)

SET IDENTITY_INSERT [Recipes] ON
GO

--
-- Dumping data for table 'Recipes'
--

INSERT INTO [Recipes] ([Id], [Caption]) VALUES (2, N'RecipeA')
INSERT INTO [Recipes] ([Id], [Caption]) VALUES (3, N'RecipeB')
INSERT INTO [Recipes] ([Id], [Caption]) VALUES (4, N'RecipeC')
-- 3 records

SET IDENTITY_INSERT [Recipes] OFF
GO

实施例: 如果我搜索ProductA和ProductE,它应该只给我RecipeC

现在我对MySQL有这样的东西(它不是最终的。我只能使用Ids操作,我不知道如何改变它只适用于产品标题并适应MSSQL)

SELECT 
    *
FROM
    recipes AS r
        INNER JOIN
    ingridients i ON i.IdRecipe = r.Id
WHERE
    i.IdProduct IN (1 , 5, 6)
GROUP BY r.Id
HAVING COUNT(*) = (SELECT 
        COUNT(*)
    FROM
        ingridients AS ing
    WHERE
        ing.IdRecipe = r.Id);

1 个答案:

答案 0 :(得分:3)

以下sql获取的配方不包含列表中的产品或P.EasyToFind = -1。

select *
From Recipes
Where Id not in
 (
 select IdRecipe
 from Ingridients I
 inner join Products P ON I.IdProduct = P.Id
 where P.Caption NOT IN ('ProductA','ProductE')
 and P.EasyToFind=0
 )

它通过一个内部查询来识别不需要的成分并获取与它们中的任何一个都不匹配的食谱。