Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 每人有两个姓名(即四个姓名)?我提出这个问题的原因是,您在最终选择中提取了四个名称,但您只映射了每个personId的两个nameId,而不考虑nameType。要么是我遗漏了什么,要么是你的疏忽。@AndriyM-两个名字(由NameID标识)由两部分组_Sql_Sql Server - Fatal编程技术网

Sql 每人有两个姓名(即四个姓名)?我提出这个问题的原因是,您在最终选择中提取了四个名称,但您只映射了每个personId的两个nameId,而不考虑nameType。要么是我遗漏了什么,要么是你的疏忽。@AndriyM-两个名字(由NameID标识)由两部分组

Sql 每人有两个姓名(即四个姓名)?我提出这个问题的原因是,您在最终选择中提取了四个名称,但您只映射了每个personId的两个nameId,而不考虑nameType。要么是我遗漏了什么,要么是你的疏忽。@AndriyM-两个名字(由NameID标识)由两部分组,sql,sql-server,Sql,Sql Server,每人有两个姓名(即四个姓名)?我提出这个问题的原因是,您在最终选择中提取了四个名称,但您只映射了每个personId的两个nameId,而不考虑nameType。要么是我遗漏了什么,要么是你的疏忽。@AndriyM-两个名字(由NameID标识)由两部分组成(一个名字和一个姓氏,由NameType标识)。啊,我现在明白我不理解的原因了!从最初的帖子中,我收集到所有链接到同一个personId的(部分)名字构成了一个名字。但您似乎将它们视为(可能)几个名字,每一对名字和姓氏构成相关personId


每人有两个姓名(即四个姓名)?我提出这个问题的原因是,您在最终选择中提取了四个名称,但您只映射了每个
personId
的两个
nameId
,而不考虑
nameType
。要么是我遗漏了什么,要么是你的疏忽。@AndriyM-两个名字(由NameID标识)由两部分组成(一个名字和一个姓氏,由NameType标识)。啊,我现在明白我不理解的原因了!从最初的帖子中,我收集到所有链接到同一个
personId
的(部分)名字构成了一个名字。但您似乎将它们视为(可能)几个名字,每一对名字和姓氏构成相关
personId
的一个单独的备选名称-是这样吗?谢谢,我只是想让我对您的方法的理解更加准确。在获得更多信息之前,谁的假设更容易出错是毫无疑问的。我一读到开头的几句话,就盯上了自己的名字:我记得我曾经读过一篇关于葡萄牙语名字有多长的文章,我至今仍对这篇文章印象深刻。显然,在做出假设时,您没有这种关联。为什么是XML,而不仅仅是MAX()[我的答案]或PIVOT[安德里姆的答案]?是否存在性能特征差异?@Dems-我只是想展示一种不同的方式来完成工作。我还没有测试过它的性能,所以我真的不知道。这实际上取决于返回的行数。应该在CTE中应用where子句来筛选行,以获得最佳性能。我不建议在视图中进行此查询,并在连接等中使用此查询。它可能会为每个问题生成整个CTE,无论是输出一行还是所有行。如果性能是一个问题,我建议在客户端执行直接查询和透视以进行表示。@Dems顺便说一句。此解决方案与流行的
for xml path
技巧非常相似,将行串联到逗号分隔的字符串中。@Dems-我查看了您和AndriyM的答案,两人都在一个单独的时间内完成了工作表格扫描。没有where子句,这是一个很好的例子+米凯勒里克森:我希望我能像你对我的回答一样对你的回答有敏锐的洞察力!对我来说,你的答案主要是有用的,因为它包含了一个使用XML的正确工作的解决方案,而我目前对XML知之甚少。由于懒于通过广泛阅读文档来学习,我目前正试图通过查看各种示例来收集尽可能多的信息。(这是我经常想到的,因此,一旦我脑子里对这一原理有了基本的理解,我就会自然而然地渴望获得更多关于这一问题的理论知识。)
PersonId | FName1 | Fname2  | Lname1    | Lname2
1          David    Daniekl   Bekernman   Stivens
   PersonId
   BirthDate
   PersonId
   NameId
   Name
   NameType (e.g; first, last...)
CREATE TABLE [dbo].[Person]
(
[PersonId] [int] PRIMARY KEY
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[PersonNames]
(
[PersonId] [int] NOT NULL,
[nameId] [int] NOT NULL,
[NAME] [varchar] (100) NOT NULL,
[NameType] [varchar] (10) NOT NULL
) ON [PRIMARY]
GO

INSERT Person VALUES(1),(2)

INSERT dbo.PersonNames(PersonId, NameId, Name, NameType)
SELECT 1,1,'John', 'first' UNION ALL
SELECT 1,1,'Doe', 'last' UNION ALL
SELECT 1,2,'Ioann', 'first' UNION ALL
SELECT 1,2,'Doeman', 'last' UNION ALL
SELECT 1,3,'Yonh', 'first' UNION ALL
SELECT 1,3,'Doesson', 'last' UNION ALL

SELECT 2,1,'John2', 'first' UNION ALL
SELECT 2,1,'Doe2', 'last' UNION ALL
SELECT 2,2,'Ioann2', 'first' UNION ALL
SELECT 2,2,'Doeman2', 'last' UNION ALL
SELECT 2,3,'Yonh2', 'first' UNION ALL
SELECT 2,3,'Doesson2', 'last' 


SELECT 
    Person.PersonId, 
    FName1.NAME FName1,
    LName1.NAME LName1,
    FName2.NAME FName2,
    LName2.NAME LName2
FROM Person
JOIN (
       SELECT 
        ROW_NUMBER() OVER (PARTITION BY PersonId ORDER BY NameId) Ordinal,
        PersonId, Name, NameId
       FROM PersonNames 
       WHERE  NameType = 'first'
     ) FName1
    ON FName1.PersonId = Person.PersonId AND FName1.Ordinal=1
JOIN PersonNames LName1
    ON LName1.PersonId = FName1.PersonId AND LName1.NameType = 'last' AND FName1.NameId = LName1.NameId
LEFT JOIN 
     (
       SELECT 
        ROW_NUMBER() OVER (PARTITION BY PersonId ORDER BY NameId) Ordinal,
        PersonId, Name, NameId
       FROM PersonNames 
       WHERE  NameType = 'first' 
     ) FName2
    ON FName2.PersonId = Person.PersonId AND FName2.NameId <> FName1.NameId AND FName2.Ordinal = 2
LEFT JOIN PersonNames LName2
    ON FName2.PersonId = LName2.PersonId AND LName2.NameType = 'last' AND LName2.NameId <> LName1.NameId AND FName2.NameId = LName2.NameId

DROP TABLE Person
DROP TABLE dbo.PersonNames
SELECT Person.PersonId
     , GROUP_CONCAT( DISTINCT first_name.Name SEPARATOR ',' ) AS first_names
     , GROUP_CONCAT( DISTINCT last_name.Name SEPARATOR ',' ) AS last_names
FROM Person
LEFT JOIN PersonName first_name ON Person.PersonId = first_name.PersonId AND first_name.Type = 'first'
LEFT JOIN PersonName last_name ON Person.PersonId = last_name.PersonId AND last_name.Type = 'last'
GROUP BY Person.PersonId
SELECT
  Person.PersonId,
  MAX(CASE WHEN Name.nameId = map.minNameId AND Name.nameType = 'first' THEN Name.Name ELSE NULL END) AS fname1,
  MAX(CASE WHEN Name.nameId = map.minNameId AND Name.nameType = 'last'  THEN Name.Name ELSE NULL END) AS lname1,
  MAX(CASE WHEN Name.nameId = map.maxNameId AND Name.nameType = 'first' THEN Name.Name ELSE NULL END) AS fname2,
  MAX(CASE WHEN Name.nameId = map.maxNameId AND Name.nameType = 'last'  THEN Name.Name ELSE NULL END) AS lname2
FROM
  Person
LEFT JOIN
  (SELECT personId, MIN(nameId) AS minNameId, MAX(nameId) as maxNameId FROM PersonNames GROUP BY PersonId) AS map
    ON map.PersonId = Person.PersonId
LEFT JOIN
  PersonNames AS Name
    On Name.PersonId = Person.PersonId
GROUP BY
  Person.PersonId
WITH
  sequenced_names AS
(
  SELECT
    DENSE_RANK() OVER (PARTITION BY PersonId ORDER BY NameID) AS NameOrdinal,
    *
  FROM
    PersonNames
)
SELECT
  PersonID,
  MAX(CASE WHEN nameOrdinal = 1 AND nameType = 'first' THEN Name END) AS fname1,
  MAX(CASE WHEN nameOrdinal = 1 AND nameType = 'last'  THEN Name END) AS lname1,
  MAX(CASE WHEN nameOrdinal = 2 AND nameType = 'first' THEN Name END) AS fname2,
  MAX(CASE WHEN nameOrdinal = 2 AND nameType = 'last'  THEN Name END) AS lname2
FROM
  sequenced_names
GROUP BY
  PersonID
;with P(PersonID, Names) as 
(
  select PersonID,
         (select NameType as '@NameType',
                 Name as '*'
          from PersonNames as PN 
          where PN.PersonId = P.PersonId
          for xml path('Name'), type)
  from Person as P
)
select P.PersonID,
       P.Names.value('(/Name[@NameType = "first"])[1]', 'varchar(100)') as FName1,
       P.Names.value('(/Name[@NameType = "last"])[1]', 'varchar(100)') as LName1,
       P.Names.value('(/Name[@NameType = "first"])[2]', 'varchar(100)') as FName2,
       P.Names.value('(/Name[@NameType = "last"])[2]', 'varchar(100)') as LName2
from P
WITH ranked AS (
  SELECT
    *,
    rnk =
      CASE NameType WHEN 'first' THEN 1 ELSE -1 END *
      ROW_NUMBER() OVER (
        PARTITION BY PersonId, NameType
        ORDER BY NameId
      )
  FROM PersonNames
  WHERE NameType IN ('first', 'last')
)
SELECT
  PersonId,
  FName1   = [1],
  FName2   = [2],
  LName1   = [-1],
  LName2   = [-2]
FROM (
  SELECT
    PersonId,
    Name,
    rnk
  FROM ranked
) s
PIVOT (
  MAX(Name) FOR rnk IN ([-2], [-1], [1], [2])
) p
WITH ranked AS (
  SELECT
    *,
    rnk =
      CASE NameType WHEN 'first' THEN 1 ELSE -1 END *
      ROW_NUMBER() OVER (
        PARTITION BY PersonId, NameType
        ORDER BY CASE NameType WHEN 'first' THEN 1 ELSE -1 END * NameId
      )
  FROM PersonNames
  WHERE NameType IN ('first', 'last')
),
SELECT
  PersonId,
  FName1   = [1],
  FName2   = [2],
  LName1   = ISNULL([-2], [-1]),
  LName2   = CASE WHEN [-2] IS NULL THEN NULL ELSE [-1] END
FROM (
  SELECT
    PersonId,
    Name,
    rnk
  FROM ranked
) s
PIVOT (
  MAX(Name) FOR rnk IN ([-2], [-1], [1], [2])
) p