表是:
+----+------+
| Id | Name |
+----+------+
| 1 | aaa |
| 1 | bbb |
| 1 | ccc |
| 1 | ddd |
| 1 | eee |
+----+------+
必需的输出:
+----+---------------------+
| Id | abc |
+----+---------------------+
| 1 | aaa,bbb,ccc,ddd,eee |
+----+---------------------+
查询:
SELECT ID,
abc = STUFF(
(SELECT ',' + name FROM temp1 FOR XML PATH ('')), 1, 1, ''
)
FROM temp1 GROUP BY id
此查询正常运行。但我只需要解释它是如何工作的,或者是否有其他或简短的方法来做到这一点。
我很难理解这一点。
答案 0 :(得分:541)
以下是它的工作原理:
<强> 1。使用FOR XML
获取XML元素字符串在查询结尾添加FOR XML PATH允许您将查询结果作为XML元素输出,其中元素名称包含在PATH参数中。例如,如果我们要运行以下语句:
SELECT ',' + name
FROM temp1
FOR XML PATH ('')
通过传入空白字符串(FOR XML PATH('')),我们得到以下内容:
,aaa,bbb,ccc,ddd,eee
<强> 2。删除带有STUFF的前导逗号
STUFF语句将一个字符串“填充”到另一个字符串中,替换第一个字符串中的字符。但是,我们只是使用它来删除结果值列表的第一个字符。
SELECT abc = STUFF((
SELECT ',' + NAME
FROM temp1
FOR XML PATH('')
), 1, 1, '')
FROM temp1
STUFF
的参数是:
所以我们最终得到:
aaa,bbb,ccc,ddd,eee
第3。加入ID以获取完整列表
接下来,我们只是在临时表的id列表中加入它,以获取名称为的ID列表:
SELECT ID, abc = STUFF(
(SELECT ',' + name
FROM temp1 t1
WHERE t1.id = t2.id
FOR XML PATH (''))
, 1, 1, '') from temp1 t2
group by id;
我们得到了结果:
-----------------------------------
| Id | Name |
|---------------------------------|
| 1 | aaa,bbb,ccc,ddd,eee |
-----------------------------------
希望这有帮助!
答案 1 :(得分:62)
This article涵盖了在SQL中连接字符串的各种方法,包括代码的改进版本,它不会对连接值进行XML编码。
SELECT ID, abc = STUFF
(
(
SELECT ',' + name
FROM temp1 As T2
-- You only want to combine rows for a single ID here:
WHERE T2.ID = T1.ID
ORDER BY name
FOR XML PATH (''), TYPE
).value('.', 'varchar(max)')
, 1, 1, '')
FROM temp1 As T1
GROUP BY id
要了解发生了什么,请从内部查询开始:
SELECT ',' + name
FROM temp1 As T2
WHERE T2.ID = 42 -- Pick a random ID from the table
ORDER BY name
FOR XML PATH (''), TYPE
因为您正在指定FOR XML
,所以您将获得一行包含表示所有行的XML片段。
因为您还没有为第一列指定列别名,所以每行都将包装在一个XML元素中,其名称在FOR XML PATH
之后的括号中指定。例如,如果您有FOR XML PATH ('X')
,那么您将获得一个类似于以下内容的XML文档:
<X>,aaa</X>
<X>,bbb</X>
...
但是,由于您还没有指定元素名称,因此您只需获取值列表:
,aaa,bbb,...
.value('.', 'varchar(max)')
只是从生成的XML片段中检索值,而不对任何&#34;特殊&#34;进行XML编码。字符。你现在有一个看起来像这样的字符串:
',aaa,bbb,...'
STUFF
函数会删除前导逗号,为您提供如下所示的最终结果:
'aaa,bbb,...'
乍一看看起来很混乱,但与其他一些选项相比,它确实表现得相当不错。
答案 2 :(得分:31)
PATH模式用于从SELECT查询生成XML
1. SELECT
ID,
Name
FROM temp1
FOR XML PATH;
Ouput:
<row>
<ID>1</ID>
<Name>aaa</Name>
</row>
<row>
<ID>1</ID>
<Name>bbb</Name>
</row>
<row>
<ID>1</ID>
<Name>ccc</Name>
</row>
<row>
<ID>1</ID>
<Name>ddd</Name>
</row>
<row>
<ID>1</ID>
<Name>eee</Name>
</row>
Output是以元素为中心的XML,其中生成的行集中的每个列值都包含在一个行元素中。由于SELECT子句未指定列名的任何别名,因此生成的子元素名称与SELECT子句中的相应列名称相同。
对于行集中的每一行,都会添加一个标记。
2.
SELECT
ID,
Name
FROM temp1
FOR XML PATH('');
Ouput:
<ID>1</ID>
<Name>aaa</Name>
<ID>1</ID>
<Name>bbb</Name>
<ID>1</ID>
<Name>ccc</Name>
<ID>1</ID>
<Name>ddd</Name>
<ID>1</ID>
<Name>eee</Name>
对于步骤2:如果指定零长度字符串,则不会生成包装元素。
3.
SELECT
Name
FROM temp1
FOR XML PATH('');
Ouput:
<Name>aaa</Name>
<Name>bbb</Name>
<Name>ccc</Name>
<Name>ddd</Name>
<Name>eee</Name>
4. SELECT
',' +Name
FROM temp1
FOR XML PATH('')
Ouput:
,aaa,bbb,ccc,ddd,eee
在第4步中,我们将值连接起来。
5. SELECT ID,
abc = (SELECT
',' +Name
FROM temp1
FOR XML PATH('') )
FROM temp1
Ouput:
1 ,aaa,bbb,ccc,ddd,eee
1 ,aaa,bbb,ccc,ddd,eee
1 ,aaa,bbb,ccc,ddd,eee
1 ,aaa,bbb,ccc,ddd,eee
1 ,aaa,bbb,ccc,ddd,eee
6. SELECT ID,
abc = (SELECT
',' +Name
FROM temp1
FOR XML PATH('') )
FROM temp1 GROUP by iD
Ouput:
ID abc
1 ,aaa,bbb,ccc,ddd,eee
在第6步中,我们按ID分组日期。
STUFF(source_string,start,length,add_string) 参数或参数 source_string 要修改的源字符串。 开始 source_string中的位置删除长度字符然后插入add_string。 长度 要从source_string中删除的字符数。 add_string 要在开始位置插入source_string的字符序列。
SELECT ID,
abc =
STUFF (
(SELECT
',' +Name
FROM temp1
FOR XML PATH('')), 1, 1, ''
)
FROM temp1 GROUP by iD
Output:
-----------------------------------
| Id | Name |
|---------------------------------|
| 1 | aaa,bbb,ccc,ddd,eee |
-----------------------------------
答案 3 :(得分:16)
Azure SQL数据库和SQL Server(从2017年开始)中有非常新的功能来处理这种确切的情况。我相信这将成为您尝试使用XML / STUFF方法完成的本地官方方法。例如:
select id, STRING_AGG(name, ',') as abc
from temp1
group by id
STRING_AGG - https://msdn.microsoft.com/en-us/library/mt790580.aspx
编辑:当我最初发布这篇文章时,我提到了SQL Server 2016,因为我认为我已经看到了一个潜在的功能。要么我记得错误或改变了某些东西,感谢建议编辑修复版本。此外,非常令人印象深刻,并没有充分意识到多步审查过程只是让我进入最后的选择。
答案 4 :(得分:3)
在 public class CommonDAOImpl{
private SessionFactory sessionFactoryCommon;
public void setSessionFactoryCommon(SessionFactory sessionFactoryCommon) {
this.sessionFactoryCommon = sessionFactoryCommon;
System.out.println("SessionFactory is set");
}
public void addMoney(String userId,double amount) {
Session session = this.sessionFactoryCommon.openSession();
try{
String hqlQuery = "HQL query to update Amount Table where userId = userId";
session.createQuery(hqlQuery).executeUpdate();
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
session.close();
}
}
public void transferMoney(String fromUserId, String toUserId, double amount)
{
Session session = null;
try
{
session = this.sessionFactoryCommon.openSession();
query = "HQL query to get previous amount from sender account";
double prevSenderamount = (double) query.uniqueResult();
if(prevAmount>=amount)
{
String query1 = "HQL query to update sender account";
session.createQuery(hqlQuery).executeUpdate();
String query1 = "HQL query to get previous amount from receiver account";
double prevReceiveramount = (double) query.uniqueResult();
String query3 = "HQL query to update receiver account";
session.createQuery(hqlQuery).executeUpdate();
}
else
{
throw myException("Insufficient Amount");
}
System.out.println("1. Employee save called without transaction, id="+id);
}
catch(Exception ex)
{
System.out.println("Exception Block");
ex.printStackTrace();
}
finally
{
session.close();
}
}
}
中,如果我们定义for xml path
之类的任何值,那么这些标记将随每行添加:
[ for xml path('ENVLOPE') ]
答案 5 :(得分:2)
SELECT ID,
abc = STUFF(
(SELECT ',' + name FROM temp1 FOR XML PATH ('')), 1, 1, ''
)
FROM temp1 GROUP BY id
在上面的查询中, STUFF 函数用于从生成的xml字符串(,)
中删除第一个逗号(,aaa,bbb,ccc,ddd,eee)
,然后它将变为(aaa,bbb,ccc,ddd,eee)
。
FOR XML PATH('')
只是将列数据转换为(,aaa,bbb,ccc,ddd,eee)
字符串,但在路径中我们正在传递&#39;&#39;所以它不会创建XML标记。
最后,我们使用 ID 列对记录进行分组。
答案 6 :(得分:1)
Declare @Temp As Table (Id Int,Name Varchar(100))
Insert Into @Temp values(1,'A'),(1,'B'),(1,'C'),(2,'D'),(2,'E'),(3,'F'),(3,'G'),(3,'H'),(4,'I'),(5,'J'),(5,'K')
Select X.ID,
stuff((Select ','+ Z.Name from @Temp Z Where X.Id =Z.Id For XML Path('')),1,1,'')
from @Temp X
Group by X.ID
答案 7 :(得分:1)
我做了调试,最后以正常的方式返回了我的'填充'查询。
简单
select * from myTable for xml path('myTable')
给我表格的内容,以便从我调试的触发器写入日志表。
答案 8 :(得分:-2)
我经常与where子句一起使用
SELECT
TapuAda=STUFF((
SELECT ','+TBL.TapuAda FROM (
SELECT TapuAda FROM T_GayrimenkulDetay AS GD
INNER JOIN dbo.T_AktiviteGayrimenkul AS AG ON D.GayrimenkulID=AG.GayrimenkulID WHERE
AG.AktiviteID=262
) AS TBL FOR XML PATH ('')
),1,1,'')
答案 9 :(得分:-2)
STUFF((从表T中选择不同的','+ CAST(T.ID),其中T.ID = 1 FOR XML PATH('')),1,1,'')AS名称