在复杂的SQL查询中使用中间联接表

问题描述

我从业务合作伙伴那里继承了一个项目,并试图将其添加到其中,但是在这里却遇到了麻烦。 这是一个由7个表格组成的鸡尾酒数据库

drinks (ID,drinkName,lu_category,lu_glassware,lu_IBA)
category (categoryID,category)
glassware (glasswareID,glassware)
ingredients (ingredientID,ingredient,notes)
measure (measureID,measure)
IBA (IBAID,IBA)
ingredient_drinks_measure (idmID,drinkID,ingredientID,measureID)

查询按预期工作,并且每杯饮料将所有内容都拉回一行。

SELECT        dbo.drinks.id AS [drinkID],dbo.drinks.drinkName,dbo.category.category,dbo.glassware.glassware,dbo.IBA.IBA,string_agg(measure.measure + ' ' + ingredients.ingredient,',') as [Ingredients]
FROM          dbo.glassware 
              RIGHT OUTER JOIN dbo.measure 
              LEFT OUTER JOIN dbo.ingredient_drinks_measure ON dbo.measure.measureID = dbo.ingredient_drinks_measure.measureID 
              RIGHT OUTER JOIN dbo.ingredients ON dbo.ingredient_drinks_measure.ingredientID = dbo.ingredients.ingredientID 
              RIGHT OUTER JOIN dbo.drinks ON dbo.ingredient_drinks_measure.drinkID = dbo.drinks.id 
              LEFT OUTER JOIN dbo.IBA ON dbo.drinks.lu_IBA = dbo.IBA.IBAID ON dbo.glassware.glasswareID = dbo.drinks.lu_glassware 
              LEFT OUTER JOIN dbo.category ON dbo.drinks.lu_category = dbo.category.categoryID
GROUP BY      dbo.drinks.id,dbo.drinks.imagePath,dbo.drinks.dateModified,dbo.IBA.IBA

返回

drinkID | drinkName | category  | glassware         | IBA                   | ingredients
11000   | Mojito    | Cocktail  | Highball glass    | Contemporary Classics | 2-3 oz Jamaican Rum,Juice of 1 Lime,2 tsp Superfine Sugar   

我现在需要在每种饮料中添加标签
(目前)只有22个标签,每种饮料都可以关联1到22个标签(这些标签包括“万圣节”,“圣诞节”,“打孔碗”,“早餐”,“晚餐聚会”,“果味”,“笨拙”等)。

我有一个tags table (id,tag)我有一个drinkTags table (drinkID,tagID)坐在中间,将饮料和标签结合在一起(两者的CREATE脚本都在下面)。

但是,无论如何尝试,当我添加查询的联接和TAGS的伴随的string_agg列(逗号分隔的聚合列)时,至少有一个string_agg列会重复和/或得到多个每杯饮料。 像这样:

drinkID | drinkName | category  | glassware         | IBA                   | ingredients
11000   | Mojito    | Cocktail  | Highball glass    | Contemporary Classics | 2-3 oz Jamaican Rum,2 tsp Superfine Sugar,2-3 oz Jamaican Rum,2 tsp Superfine Sugar

或者这个:

drinkID | drinkName | category  | glassware         | IBA                   | tags      | ingredients
11000   | Mojito    | Cocktail  | Highball glass    | Contemporary Classics | Alcoholic | 2-3 oz Jamaican Rum,2 tsp Superfine Sugar
11000   | Mojito    | Cocktail  | Highball glass    | Contemporary Classics | IBA       | 2 tsp Superfine Sugar,2-3 oz Jamaican Rum
11000   | Mojito    | Cocktail  | Highball glass    | Contemporary Classics | USA       | 2-3 oz Jamaican Rum,2 tsp Superfine Sugar

有什么想法吗?即使能为我提供我在所有研究中都被忽略的东西,我也将不胜感激。

如果需要,这里是CREATE脚本。

/****** Object:  Table [dbo].[drinks]    Script Date: 9/15/2020 1:25:57 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[drinks](
    [id] [int] IDENTITY(1,1) NOT NULL,[drinkName] [varchar](37) NOT NULL,[lu_category] [int] NULL,[lu_IBA] [int] NULL,[lu_glassware] [int] NULL
 CONSTRAINT [PK__drinks_c__2B658F5CD9E4315A] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF,STATISTICS_norECOmpuTE = OFF,IGnorE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON,OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

/****** Object:  Table [dbo].[category]    Script Date: 9/15/2020 1:27:18 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[category](
    [categoryID] [int] IDENTITY(1,[category] [nvarchar](50) NULL,CONSTRAINT [PK__category__23CAF1F80317C8FA] PRIMARY KEY CLUSTERED 
(
    [categoryID] ASC
)WITH (PAD_INDEX = OFF,OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO



/****** Object:  Table [dbo].[drinkTags]    Script Date: 9/15/2020 1:27:54 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[drinkTags](
    [drinkID] [int] NOT NULL,[tagID] [int] NOT NULL,CONSTRAINT [PK_drinkTags_1] PRIMARY KEY CLUSTERED 
(
    [drinkID] ASC,[tagID] ASC
)WITH (PAD_INDEX = OFF,OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO




/****** Object:  Table [dbo].[glassware]    Script Date: 9/15/2020 1:28:08 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[glassware](
    [glasswareID] [int] IDENTITY(1,[glassware] [nvarchar](50) NULL,PRIMARY KEY CLUSTERED 
(
    [glasswareID] ASC
)WITH (PAD_INDEX = OFF,OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO



/****** Object:  Table [dbo].[IBA]    Script Date: 9/15/2020 1:28:19 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[IBA](
    [IBAID] [int] IDENTITY(1,[IBA] [nvarchar](50) NULL,PRIMARY KEY CLUSTERED 
(
    [IBAID] ASC
)WITH (PAD_INDEX = OFF,OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO



/****** Object:  Table [dbo].[ingredient_drinks_measure]    Script Date: 9/15/2020 1:28:32 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[ingredient_drinks_measure](
    [idmID] [int] IDENTITY(1,[drinkID] [int] NULL,[ingredientID] [int] NULL,[measureID] [int] NULL,PRIMARY KEY CLUSTERED 
(
    [idmID] ASC
)WITH (PAD_INDEX = OFF,OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO



/****** Object:  Table [dbo].[ingredients]    Script Date: 9/15/2020 1:28:44 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[ingredients](
    [ingredientID] [int] IDENTITY(1,[ingredient] [nvarchar](150) NULL
PRIMARY KEY CLUSTERED 
(
    [ingredientID] ASC
)WITH (PAD_INDEX = OFF,OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXtimage_ON [PRIMARY]
GO



/****** Object:  Table [dbo].[measure]    Script Date: 9/15/2020 1:29:14 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[measure](
    [measureID] [int] IDENTITY(1,[measure] [nvarchar](50) NULL,PRIMARY KEY CLUSTERED 
(
    [measureID] ASC
)WITH (PAD_INDEX = OFF,OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO



/****** Object:  Table [dbo].[tags]    Script Date: 9/15/2020 1:29:25 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[tags](
    [id] [int] IDENTITY(1,[tag] [nvarchar](50) NOT NULL,CONSTRAINT [PK_drinkTags] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF,OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

解决方法

解决方案1:

饮料与标签是否存在一对一关系?如果是这样,那么您要做的就是在饮料表中添加一个标签列。这将是解决问题的非规范化方法。

解决方案2:

如果饮料与标签实体没有一对一的关系。
哪个表存储饮料和标签之间的关系?如果没有此表,则需要创建一个表并填充数据。如果您在创建饮料标签关系方面需要帮助,那么我可以为您提供帮助。然后,您将需要更新SQL以使用标签喝酒关系来获取单个记录,并在SQL中添加标签字段。

,

希望以下查询可以解决您的问题。我添加了一个string_agg字段以返回与饮料相关的所有标签和两个INNER JOINS。

SELECT        dbo.drinks.id AS [drinkID],dbo.drinks.drinkName,dbo.category.category,dbo.glassware.glassware,dbo.IBA.IBA,string_agg(measure.measure + ' ' + ingredients.ingredient,',') as [Ingredients],string_agg(dbo.tags.tag,‘) as [Tags]
FROM          dbo.glassware 
              RIGHT OUTER JOIN dbo.measure 
              LEFT OUTER JOIN dbo.ingredient_drinks_measure ON dbo.measure.measureID = dbo.ingredient_drinks_measure.measureID 
              RIGHT OUTER JOIN dbo.ingredients ON dbo.ingredient_drinks_measure.ingredientID = dbo.ingredients.ingredientID 
              RIGHT OUTER JOIN dbo.drinks ON dbo.ingredient_drinks_measure.drinkID = dbo.drinks.id 
              LEFT OUTER JOIN dbo.IBA ON dbo.drinks.lu_IBA = dbo.IBA.IBAID ON dbo.glassware.glasswareID = dbo.drinks.lu_glassware 
              LEFT OUTER JOIN dbo.category ON dbo.drinks.lu_category = dbo.category.categoryID
          INNER JOIN  dbo.drinkTags.drinkID =  dbo.drinks.id    
          INNER JOIN  dbo.tags.id = dbo.drinkTags.tagID
GROUP BY      dbo.drinks.id,dbo.drinks.imagePath,dbo.drinks.dateModified,dbo.IBA.IBA
,

经过大量研究,我找到了一个适用于我的解决方案。这确实假定每个DrinkID至少有一个标签,但是我现在可以处理。

;WITH a AS
(
SELECT 
    d.id,d.drinkName as [Name],c.category as [Category],g.glassware as [Glass],b.IBA as [IBA],string_agg(m.measure + ' ' + i.ingredient,d.instructions as [Instructions],string_agg(i.notes,') as [IngredientNotes],d.addedInfo as [Additional Information],d.imagePath as [Image]
FROM drinks d
    JOIN category c on c.categoryID = d.lu_category
    JOIN glassware g on g.glasswareID = d.lu_glassware
    LEFT JOIN IBA b on b.IBAID = d.lu_IBA
    JOIN ingredient_drinks_measure idm on idm.drinkID = d.id
    JOIN ingredients i on i.ingredientID = idm.ingredientID
    JOIN measure m on m.measureID = idm.measureID
group by d.id,d.drinkName,c.category,g.glassware,b.IBA,d.addedInfo,d.imagePath,d.instructions
)
SELECT a.*,dtm.tags
FROM a
JOIN (select 
        drinkID,string_agg(t.tag,') as tags
        from tags t
        join tagmap tm on tm.tagID = t.id
        group by drinkID) as dtm
ON a.ID = dtm.drinkID