在SQL中为选定的重复值添加字符

时间:2015-02-05 14:11:13

标签: sql sql-server duplicates return-value

我需要为选定的重复值添加字符/数字。

这就是我需要的:

SELECT Name -- Here I need to add for example 1 if It have duplicates
            -- If It is hard way to code, how to add 1 to all selected values?
FROM Example
WHERE Id BETWEEN 25 AND 285

如果有2个相同的名称Peter则应选择Peter和第二个Peter1

如果没有简单的方法来制作它,如何将1添加到所有选定的行?应选择Peter1而不是Peter

我试过这个:

SELECT Name + ' 1' AS Name -- in this case selecting wrong column
FROM Example
WHERE Id BETWEEN 25 AND 285

修改

SELECT @cols += ([Name]) + ','
    FROM   (SELECT  Name --I neeed to integrate It here
            FROM    FormFields
            WHERE   ID BETWEEN 50 AND 82
            ) a 

如果我使用它:

SELECT @cols += ([Name]) + ',' -- here throws error
FROM   (SELECT Name + CASE WHEN RowNum = 1 THEN '' ELSE CONVERT(NVARCHAR(100), RowNum-1) END AS [UpdatedName]
                FROM (
                SELECT  Name AS Name,  
                        ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Name) AS "RowNum"
                FROM    FormFields
                WHERE   Id Between 50 And 82) x
        ) a

抛出错误:Invalid column name 'Name'.

编辑2

它的测试不同,但其中一些测试标准相同。这就是我需要重命名的原因。 howshouldbe

4 个答案:

答案 0 :(得分:5)

您可以通过Row_Number并使用Case来完成此操作。以下是SQL Server的示例:

;With Cte As
(
    Select  Name, Row_Number() Over (Partition By Name Order By Name) RN
    From    Example
    Where   Id Between 25 And 285
)
Select  Case When RN = 1 Then Name Else Name + Cast((RN - 1) As Varchar (3)) End As Name
From    Cte

答案 1 :(得分:1)

您可以使用SQL Server中内置的ROW_NUMBER函数。

select Name + case when RowNum = 1 then '' else CONVERT(varchar(100), RowNum-1) end as "UpdatedName"
from (
select name as "Name",  
       ROW_NUMBER() over (partition by name order by name) as "RowNum"
from Example
Where   Id Between 25 And 285) x

请注意,这仍然不能保证您的名字。毕竟,有人可能已经有了#34; MyName1"的名字,所以如果你有2个人的名字" MyName"你还得到2" MyName1"用这个select语句。

答案 2 :(得分:1)

这是一个非常不寻常的要求,看起来你正试图让汽车在车顶上用轮子行驶" :)

根本问题几乎肯定是错误的数据库设计...... Pivot通常用于数据摘要。如果你在同一列中,彼得"和彼得"它具有不同的含义,看起来有些不对劲。或者您是否因任何其他原因需要区分彼得斯?

我不明白你想要达到的目标。如果彼得总是彼得,并且你只是想避免重复,你可以简单地使用"按名称分组"。但这就是枢轴自动完成的......如果彼得和彼得有两种不同的含义(如Peter1和Peter2),你应该考虑改变数据库结构,如果可能的话。

或者尝试更深入地解释你想要实现的目标。

编辑:

好的,现在我理解了所需的输出。您的源数据表的结构是什么?从您的架构中可以看出,您需要根据

创建PIVOT列
Testname+groupId 

Testname+convert(varchar(100),groupId)

如果groupId是数字。那是你的Peter1,Peter2的组合。它将创建您需要的列。但我不知道testname和groupId在数据表中的位置。测试名称是否与列NAMES或存储在DB中的VALUES相对应? groupId有类似TestId吗?列还是值?提供有关源数据结构的更多信息,如果您需要更多帮助,您的问题就不那么复杂了。

答案 3 :(得分:1)

由于列具有组ID,因此将列名称与Underscore和GroupID连接为键值,并在显示时删除下划线和尾随字符。

喜欢这个:

SELECT @cols += ([Name]) + ','
FROM   (SELECT  Name + '_' + CAST(GroupId AS varchar)
        FROM    FormFields
        WHERE   ID BETWEEN 50 AND 82
        ) a 

我假设您正在使用它来构建动态SQL语句。我不确定FormFields表的模式是什么,但如果它包含类似测试名称的内容,您可以附加AS [Name] +' - '+ [TestName]以使列标题更有用。我会说尝试PIVOT,但如果测试没有大多数共同的领域,那可能会非常笨拙......

我还假设您在这些提示中存储对这些提示的响应,如下所示:

CREATE TABLE [Responses]
(
 RespID int IDENTITY NOT NULL,
 UserID int NOT NULL,
 FieldID int NOT NULL,
 RespVal int/varchar/whatever NOT NULL
)

然后,您可能有一个[Test]表,其中包含一些测试元数据,这些元数据充当FormFields表中GroupID外键的主键。

在您的示例中,您显示了所有列的回复,但我不确定这是如何工作的(除非我在您的解释中遗漏了一些内容以及我对您的设计做出的推断)一组回复只能为每行的一个组填充,除非您要汇总响应,但是按照什么标准?行可能与受访者相对应,所有受访者都需要回答所有表单类型。在这种情况下,您的输出将像这样的PIVOT:

DECLARE @sql varchar(4000) = ''
DECLARE @colList varchar(1000)
DECLARE @selList varchar(1000)

;WITH NameBase 
AS
(
  SELECT t.Name [TestName], f.Name [FieldName], f.GroupId
  FROM [FormFields] f
  INNER JOIN [Tests] t ON f.GroupID = t.ID
)
SELECT @colList = COALESCE(@colList + ',','') + QUOTENAME([FieldName] + '_' + [GroupId])
, @selList = COALESCE(@selList + ',','') + QUOTENAME([FieldName] + '_' + [GroupId]) + ' AS ' + QUOTENAME([FieldName] + ' - ' + [TestName])
FROM NameBase

SELECT @sql = 'SELECT [UserName],' + @selList + ' FROM (
SELECT u.Name [UserName], f.Name + '_' + f.GroupId [FieldName], r.RespVal [Response]
FROM Responses r
INNER JOIN [TestUsers] u ON r.UserID = u.ID
INNER JOIN [FormFields] f ON r.FieldID = f.ID) t
PIVOT (MAX([Response]) FOR [FieldName] IN (' + @colList + ')) pvt'

EXECUTE(@sql);

我还没有测试过,但它至少应该指向正确的方向。我将尝试构建一个SqlFiddle以稍微测试它。