【问题标题】:Generate missing rows using JOIN / CROSS JOIN使用 JOIN / CROSS JOIN 生成缺失的行
【发布时间】:2020-03-02 16:23:12
【问题描述】:

我有 3 个表格用于填充动态值。

该表由下面的架构表示。

用户可以添加尽可能多的行,并且这些行通过 FormField 表中的模板显示给最终用户。

FormValues 中保存的数据仅用于非空值,任何缺失的值都不会保存。

现在的问题是我必须按预期生成报告。

我尝试了各种连接/交叉连接的组合,但都没有按预期工作。

我可以通过循环在 C# 中实现这一点,但不能通过 SQL Server 做到这一点。

为 DB 附加的脚本

USE [SampleDb]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FormTemplate](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_FormTemplate] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)
) ON [PRIMARY]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FormField](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [FormId] [int] NOT NULL,
    [FieldName] [nvarchar](50) NULL,
    [FieldType] [nvarchar](50) NULL,
 CONSTRAINT [PK_FormField] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[FormTemplate]    Script Date: 3/2/2020 10:10:22 PM ******/

/****** Object:  Table [dbo].[FormValue]    Script Date: 3/2/2020 10:10:22 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FormValue](
    [FormId] [int] NOT NULL,
    [FieldId] [int] NOT NULL,
    [RowIndex] [int] NOT NULL,
    [FormValue] [nvarchar](50) NULL,
 CONSTRAINT [PK_FormValue] PRIMARY KEY CLUSTERED 
(
    [FormId] ASC,
    [FieldId] ASC,
    [RowIndex] ASC
)
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[FormField] ON 
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (1, 1, N'FirstName', N'string')
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (2, 1, N'LastName', N'string')
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (3, 1, N'Place', N'string')
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (4, 1, N'age', N'int')
GO
INSERT [dbo].[FormField] ([Id], [FormId], [FieldName], [FieldType]) VALUES (5, 1, N'dob', N'date')
GO
SET IDENTITY_INSERT [dbo].[FormField] OFF
GO
SET IDENTITY_INSERT [dbo].[FormTemplate] ON 
GO
INSERT [dbo].[FormTemplate] ([Id], [Name]) VALUES (1, N'Sample')
GO
SET IDENTITY_INSERT [dbo].[FormTemplate] OFF
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 1, 1, N'fname1')
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 2, 1, N'lname1')
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 2, 3, N'lname3')
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 4, 5, N'20')
GO
INSERT [dbo].[FormValue] ([FormId], [FieldId], [RowIndex], [FormValue]) VALUES (1, 5, 3, N'10/10/2020')
GO

【问题讨论】:

  • “我尝试了多种连接/交叉连接的组合,但都没有按预期工作。” 向我们展示这些尝试。 CROSS JOIN 似乎正是您想要的。另外,请不要将示例数据发布为图像;拥有 18K 声誉的人现在应该不能使用它。 DDL 和 DML 语句更受欢迎,或者最坏的情况是表格格式 text
  • @Larnu - 将附加脚本。
  • use text, not images/links, for text--including tables & ERDs。转述或引用其他文本。只提供您需要的东西并将其与您的问题联系起来。仅将图像用于无法表达为文本或增强文本的内容。无法搜索或剪切和粘贴图像。在图像中包含图例/键和说明。格式化为标题加行的 PS 表初始化代码使图像变得不必要。
  • 这个不清楚。使用足够多的单词、句子和对部分示例的引用来清楚完整地表达你的意思。描述结果:说足够多的人可以离开并带着解决方案回来并且用户知道如何使用它。在给出业务关系(船舶)/关联或表(基础或查询结果)时,说明其中的一行根据其列值说明了业务情况。请在代码问题中提供minimal reproducible example。展示你尝试过的东西。请不要要求我们编写您的代码。
  • 当你得到一个你不期望/不理解的结果时,停止试图找到你的总体目标并找出你的误解。--隔离第一个意外/误解的子表达式及其输入和输出并学习是什么误解、错字、错误的推理等导致了它。 (调试基础。)询问一下。似乎当明确这将是一个常见问题解答。在考虑发布之前,请始终在谷歌上搜索任何错误消息或您的问题/问题/目标的许多清晰、简洁和精确的措辞,带有和不带有您的特定字符串/名称和站点:stackoverflow.com 和标签;阅读许多答案。 How to Ask

标签: sql sql-server join common-table-expression


【解决方案1】:

这回答了问题的原始版本——然后是一些。但我不会更新答案以适应不断变化的问题。

您似乎希望在三个“表”上进行交叉连接。第三个需要生成rowindex的值:

select f.id as formtemplateid, ff.id as formfieldid, v.rowindex,
       fv.value
from formtemplate f cross join
     formfield ff cross join
     (values (1), (2), (3), (4), (5)) v(rowindex) left join
     formvalues fv
     on fv.formtemplateid = f.id and
        fv.formfieldid = ff.id and
        fv.rowindex = v.rowindex
order by f.id, ff.id, v.rowindex;

编辑:

您可以使用递归 CTE 生成多达 100 个数字,方法是:

with n as (
      select 1 as n
      union all
      select n + 1
      from n
      where n < 10  -- "10" is however many you want
     )
select n.n
from n;

【讨论】:

  • 这看起来很棒,有没有什么方法可以动态实现values (1), (2), (3), (4), (5),就像没有任何行一样
  • @ParimalRaj 。 . . (1) 那将是一个不同的问题。 (2) 您可以使用递归 CTE 或数字表。
  • 关于 CTE 的任何提示?,即使是粗略的想法也可以,我会尝试看看我的结局。
  • 让我试一试!感谢您提供如此快速的帮助。
  • 似乎无法在一个查询中完成,除非 rowindex 上的交叉连接不能是动态的,这似乎是不可能的,
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-19
  • 2014-06-23
  • 1970-01-01
  • 2019-09-03
  • 2020-04-21
相关资源
最近更新 更多