Sql server 乱七八糟的桌子
我在SQL Server中有一个凌乱的表(对不起,这是我从供应商那里得到它的方式)。我已经把它大大简化了,这样我就可以集中精力解决这个问题,尽管我显然已经看不见森林了 目标:虽然我似乎无法得到正确的逻辑,但有点取消了这些数据。Sql server 乱七八糟的桌子,sql-server,Sql Server,我在SQL Server中有一个凌乱的表(对不起,这是我从供应商那里得到它的方式)。我已经把它大大简化了,这样我就可以集中精力解决这个问题,尽管我显然已经看不见森林了 目标:虽然我似乎无法得到正确的逻辑,但有点取消了这些数据。 问题:奇怪的是,我需要列标题的子字符串作为数据的一部分-如下面的示例所示 Rextester示例数据 导入后,我的表如下所示: +----+----------+--------------------+--------------------+-------------
问题:奇怪的是,我需要列标题的子字符串作为数据的一部分-如下面的示例所示 Rextester示例数据 导入后,我的表如下所示:
+----+----------+--------------------+--------------------+-------------------+-------------------+
| id | person | contact 1 - phone | contact 2 - phone | contact 1 - email | contact 2 - email |
+----+----------+--------------------+--------------------+-------------------+-------------------+
| 1 | john doe | 123456 | 234567 | john@doe.me | johndoe@gmail.com |
| 2 | jane doe | 654321 | 765432 | Jane@doe.me | NULL |
+----+----------+--------------------+--------------------+-------------------+-------------------+
预期产出:
+----+----------+---------------+--------+-------------------+
| id | person | contactNumber | phone | email |
+----+----------+---------------+--------+-------------------+
| 1 | John Doe | 1 | 123456 | john@doe.me |
| 1 | John Doe | 2 | 234567 | johndoe@gmail.com |
| 2 | Jane Doe | 1 | 654321 | jane@doe.me |
| 2 | Jane Doe | 2 | 765432 | janedoe@gmail.com |
+----+----------+---------------+--------+-------------------+
如果联系人2的电子邮件或电话不为空,您可以使用
UNION
生成联系人1的所有记录和联系人2的所有记录。如果contact-2的电子邮件为空,则使用COALESCE
使用contact-1的电子邮件
SELECT id, person, 1 [contactNumber], [contact 1 - phone] [phone], [contact 1 - email] [email]
FROM #TEST
UNION
SELECT id, person, 2
, [contact 2 - phone]
, COALESCE([contact 2 - email], [contact 1 - email])
FROM #TEST
WHERE [contact 2 - phone] IS NOT NULL OR [contact 2 - email] IS NOT NULL
你试过这个吗
SELECT
id,
person,
1 as contactnumber,
[contact 1 - phone] as phone,
[contact 1 - email] as email
FROM Table
UNION
SELECT
id,
person,
2 as contactnumber,
[contact 2 - phone] as phone,
[contact 2 - email] as email
FROM Table
以防你需要“动态”,也就是说,你不知道专栏(或联系人)如何 示例
Declare @YourTable Table ([id] varchar(50),[person] varchar(50),[contact 1 - phone] varchar(50),[contact 2 - phone] varchar(50),[contact 1 - email] varchar(50),[contact 2 - email] varchar(50))
Insert Into @YourTable Values
(1,'john doe',123456,234567,'john@doe.me','johndoe@gmail.com')
,(2,'jane doe',654321,765432,'Jane@doe.me',NULL)
Select id
,person
,contactNumber
,phone = max(case when Item like '%phone%' then value end)
,email = max(case when Item like '%email%' then value end)
From (
Select A.ID
,A.Person
,contactNumber = cast(substring(Item,patindex('%[0-9]%',item),2) as int)
,C.*
From @YourTable A
Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
Cross Apply (
Select Item = replace(a.value('local-name(.)','varchar(100)'),'_x0020_',' ')
,Value = a.value('.','varchar(max)')
From B.XMLData.nodes('/row') as C1(n)
Cross Apply C1.n.nodes('./@*') as C2(a)
Where a.value('local-name(.)','varchar(100)') not in ('id','person')
) C
) A
Group By id,person,contactNumber
返回
编辑-简化
返回
您忘记了从句a中的答案,因此,它基本上与我的答案相同。从句a中,我希望联系人2出现,但如果没有,我希望为空-联合会再次给我第一个-我不希望这样。好的。我更改了我的答案,所以电话将为空。使用
COALESCE
,它仍然显示第一个联系人电子邮件地址,如果第二个是null
,这就是您在问题中的示例的工作原理。你可以随意摆脱它。我需要变得有活力——所以这似乎是有道理的。还需要消化。我喜欢您的许多答案(有相当一部分)都使用同一个工具的方式-强制转换为XML,交叉应用节点。@Eli如您所知,SQL Server在设计上是声明性的。当然,您可以使用经典的动态SQL(这可能更有效),但我喜欢XML方法的一点是它没有范围问题,XML/源可以是表、视图,甚至是带有派生列的自定义查询。例如,我有一个表值函数,它可以将几乎任何select转换为EAV结构。作为一个TVF,它可以被合并到交叉应用程序中,也可以被另一个查询使用。我试图将您的概念实现到实际数据集中,但是,我遇到了一些问题,“contactnumber”字段返回非数值,他们在转换失败等情况下破坏了查询。我在第二个交叉应用中的“不在”部分添加了我不希望“取消插入”的所有字段,但没有用:(@Eli显然,我们在列名中有一些意外的值/格式。请参阅编辑简化版。也许这将有助于任务/开发这就是我开始的地方…我需要“contact”一词后面的值。我尝试编辑您的“where a.value('local-name(.),'varchar(100)”,而不是('id','person')行)`要使所有字段都不以contact开头,尽管它仍在拾取一些值。。。
Select A.ID
,A.Person
,C.*
From @YourTable A
Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
Cross Apply (
Select Item = replace(a.value('local-name(.)','varchar(100)'),'_x0020_',' ')
,Value = a.value('.','varchar(max)')
From B.XMLData.nodes('/row') as C1(n)
Cross Apply C1.n.nodes('./@*') as C2(a)
Where a.value('local-name(.)','varchar(100)') not in ('id','person')
) C