1

我目前有一个用户表tblUser和一个用户类型表,tblUserTypes.

两者之间通过外键链接进行链接tblUser... fkUserTypeID

因此,目前用户只能是一种类型。

但是,在某些情况下,用户可以是多种类型……例如,aCustomerSupplier.

tblUser对我来说显而易见的解决方案是在and之间创建一个新表tblUserTypestblUser_UserTypes这是一个桥接表:

[tblUser] ---< [tblUser_UserTypes] >--- [tblUserTypes]

但是,我可以看到由此产生的复杂性......例如,当导出加入其用户类型的用户列表时,通过直接加入,我最终会得到多行这些用户。也许可以使用 PIVOT 查询将每个用户记录带回单行?(更多关于这个)

将用户导入系统似乎也有问题......我目前正在使用BCP文件中的(批量复制过程)将用户直接导入用户表......导入文件包含单个字段“用户类型”,它在现有模型,因为每个用户当前只能是一种类型。但是,对于多种用户类型,我看不到直接进入用户表的直接 BCP 是如何工作的。

增加复杂性的是用户类型当前不是固定的......表 tblUserTypes 是动态的......系统的一部分是允许创建任意数量的用户类型。但是,我需要了解某些类型的用户才能在更高级别定义业务逻辑......例如“仅允许该区域中 type=x 的用户”......所以有人建议在用户类型表中有一系列标志定义用户类型是什么类型(例如IsCustomerIsSupplier

这感觉就像一个过于复杂的混乱,我正在为如何前进而失眠。

我很想将用户类型带回表中tblUser并完全取消其他两个表......用户表中的一系列复选框(例如IsCustomerIsSupplier)......因为这样可以直接导入和导出。但是,用户类型不会是动态的。有趣的是,虽然用户类型不是完全动态的......因为如上所述,当涉及到业务登录时,我需要了解一些用户类型。

嗯,它应该是两者的混合体吗?我是否试图将两个功能合并为一个?也许我可以在用户表中为与业务逻辑相关的类型(例如IsCustomer, )设置复选框/布尔类型,并重命名toIsSupplier的上下文或类似的东西。"User Types""User Groups"

对我来说,一个主要问题是在考虑直接连接将导致用户被复制的结构时对导入、导出和搜索结果的影响......他们所属的每种用户类型对应一行。我必须进行 PIVOT 查询才能将其恢复到每个用户的一条记录,每个用户类型都有一个列,不是吗?一个现实的例子是一个包含 300 万条记录的用户表,一次导入 10,000 条记录……或一次导出 10,000 条记录……或搜索这 300 万条记录以检索 3,000 条匹配项并将其呈现在网页上以分页方式,他们可以浏览搜索结果页面(我ROWNUM在搜索查询中使用分页,我不会每次都返回全部内容)。

这是我关于 Stack Overflow 的第一个问题,如果它有点令人费解或者已经列出了答案,我很抱歉......我试图搜索但无法提出处理与用户合作的复杂性的示例多种类型。

哦,以防万一……这是一个使用 SQL Server 的 C# ASP.NET 应用程序。


在仔细考虑并阅读回复后,我将一路走来使用桥接表......要求说用户可以是多种类型,所以它就是这样。对现有代码的影响是巨大的,但现在比走下坡路要好。

我玩弄了表结构,在平面结构中获取数据所需的查询有点繁琐,最终需要动态 SQL(因为用户类型的列表是动态的)我不喜欢但我可以没有看到另一种方法来做到这一点。

在下面的示例中,获取的公司由“事件 ID”过滤,即 fkEventID

如果有更好的方法来做“扁平化”,我会非常感谢任何帮助:-)


直接连接(如果它们属于一种以上类型,则每个公司多行)

select * from tblCompany 
left join tblCompany_CompanyType on fkCompanyID = pkCompanyID
left join tblCompanyType on fkCompanyTypeID = pkCompanyTypeID
where tblCompany.fkEventID = 1


硬编码数据透视查询(如果它们属于一种以上类型,则每个公司单行,但公司类型不是动态的)

select * from (
select tblCompany.*,tblCompanyType.CompanyType from tblCompany left join
tblCompany_CompanyType on fkCompanyID = pkCompanyID
left join tblCompanyType on fkCompanyTypeID = pkCompanyTypeID
where tblCompany.fkEventID = 1
) AS sourcequery
Pivot (count(CompanyType) for CompanyType IN ([Customer],[Supplier],[Something Else])) as CompanyTypeName


动态透视查询(每个公司多行并处理动态公司类型)

DECLARE @cols AS NVARCHAR(MAX)
DECLARE @sql  AS NVARCHAR(MAX)

SET @cols = STUFF(
(SELECT N',' + QUOTENAME(CompanyType) AS [text()]
FROM (
select CompanyType from tblCompanyType
where fkEventID = 1
) AS Y
FOR XML PATH('')),
1, 1, N'');

SET @sql = N'SELECT * FROM (
select tblCompany.*,tblCompanyType.CompanyType from tblCompany left join tblCompany_CompanyType on fkCompanyID = pkCompanyID
left join tblCompanyType on fkCompanyTypeID = pkCompanyTypeID
where tblCompany.fkEventID = 1
) AS sourcequery
Pivot (count(CompanyType) for CompanyType IN (' + @cols + ')) as CompanyTypeName
order by pkCompanyID'

EXEC sp_executesql @sql;
4

1 回答 1

0

您确实在用户和用户类型之间存在多对多关系,我建议您继续以这种方式实现它。

如果您需要在某些情况下看到它变平,您可以使用视图或存储过程来适应它。

如果您想继续使用 BCP 导入,您始终可以将 BCP 导入临时表,然后使用存储的过程来填写您的 3 个表。无论如何,这样做可能更安全。

保持完全实现多对多关系将为您的应用程序提供最大的灵活性,并防止您在获得对新安全角色的新要求时不断修改用户表。

于 2013-03-06T01:06:36.653 回答