我在MS-SQL(使用SQL Server 2014 Standard)中有一个数据表,其中包含以下说明性布局(遗憾的是无法更改):
<div ng-form="parentForm">
<div ng-repeat="item in items" ng-form="itemForm">
<input type="text" ng-model="item.name" required/>
</div>
<input type="submit" ng-disabled="parentForm.$invalid" />
</div>
我需要使用以下输出创建查询:
ID Score Segmentation
1 | 500 | GROUP 1 - SET A - 50%; GROUP 2 - 25%; GROUP 1 - SET G - 25%
2 | 200 | GROUP 1 - SET B - 25%; GROUP 5 - SET A - SET B - 50%; GROUP 6 - 25%
也就是说,结果集应该显示每个唯一的组,总计得分,由组在每一行中的总百分比构建(即组1总分为500 * 0.5 + 500 * 0.25 + 200 * .25 = 425)。数据上的参数是;
我之前在https://blog.sqlauthority.com/2015/04/21/sql-server-split-comma-separated-list-without-using-a-function/发现了一个解决方案,但它似乎有所突破,并且不喜欢&#39;&amp;&#39;字符。
我很感激有关如何解决此问题的任何想法。
谢谢!
答案 0 :(得分:1)
在SQL Server中基本上有三种方法:
专业字符可能会影响XML处理,但它们应该适用于前两个。
例如:
with cte as (
select id, score,
left(segmentation, charindex(';', segmentation + ';') - 1) as segment,
substring(segmentation, charindex(';', segmentation + ';') + 1, len(segmentation)) + ';' as rest
from t
union all
select id, score,
left(rest, charindex(';', rest + ';') - 1) as segment,
substring(rest, charindex(';', rest) + 1, len(rest))
from cte
where rest like '%;'
)
select left(segment, charindex(' - ', segment)) as segmentation,
sum(score * cast(replace(right(segment, charindex(' ', reverse(segment, ' ')) - 1), '%', '') as float) / 100.0) as TotalScore
from cte
group by left(segment, charindex(' - ', segment));
这样做了很多奇怪的字符串处理,因为数据结构很糟糕。我鼓励你努力修复数据结构,以便数据更有用。
答案 1 :(得分:1)
MS SQL Server 2014架构设置:
CREATE TABLE t(ID INT , Score INT , Segmentation VARCHAR(1000))
INSERT INTO t VALUES
(1 , 500 , 'GROUP 1 - SET A - 50%; GROUP 2 - 25%; GROUP 1 - SET G - 25%'),
(2 , 200 , 'GROUP 1 - SET B - 25%; GROUP 5 - SET A - SET B - 50%; GROUP 6 - 25%')
查询1 :
SELECT Groups
,SUM(CAST( Score * REPLACE(Percentage , '%','') /100.0 AS decimal(18,2))) Total_Score
FROM
(
SELECT ID
,Score
,LEFT(RTRIM(LTRIM(Split.a.value('.', 'VARCHAR(100)'))), 8) Groups
,RIGHT(RTRIM(LTRIM(Split.a.value('.', 'VARCHAR(100)'))),4) Percentage
FROM
(SELECT ID
, Score
, Cast ('<X>' + Replace(Segmentation, ';', '</X><X>') + '</X>' AS XML) AS Data
FROM t
) AS t CROSS APPLY Data.nodes ('/X') AS Split(a)
) q
GROUP BY Groups
<强> Results 强>:
| Groups | Total_Score |
|----------|-------------|
| GROUP 1 | 425 |
| GROUP 2 | 125 |
| GROUP 5 | 100 |
| GROUP 6 | 50 |
答案 2 :(得分:0)
使用CROSS APPLY的另一个选项。我应该注意,这个拆分/解析是XML安全的。
我不知道第3组来自哪里(也许是一个错字?)
Declare @YourTable table (ID int,Score int,Segmentation varchar(100))
Insert Into @YourTable values
(1 , 500 , 'GROUP 1 - SET A - 50%; GROUP 2 - 25%; GROUP 1 - SET G - 25%'),
(2 , 200 , 'GROUP 1 - SET B - 25%; GROUP 5 - SET A - SET B - 50%; GROUP 6 - 25%')
Select B.Segmentation
,Total_Score = sum((A.Score*B.Value)/100)
From @YourTable A
Cross Apply (
Select Segmentation = left(RetVal,charindex(' - ',RetVal))
,Value = cast(replace(reverse(left(reverse(RetVal),charindex(' - ',reverse(RetVal)))),'%','') as float)
From (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(A.Segmentation,';','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
) C1
) B
Group By B.Segmentation
返回
Segmentation Total_Score
GROUP 1 425
GROUP 2 125
GROUP 5 100
GROUP 6 50
答案 3 :(得分:0)
您可以尝试遵循基于XML / XQuery的解决方案:
DECLARE @Table1 TABLE (
ID INT,
Score INT,
Segmentation VARCHAR(1000)
)
INSERT INTO @Table1
VALUES
(1 , 500 , 'GROUP 1 - SET A - 50%; GROUP 2 - 25%; GROUP 1 - SET G - 25%'),
(2 , 200 , 'GROUP 1 - SET B - 25%; GROUP 5 - SET A - SET B - 50%; GROUP 6 - 25%')
SELECT t.GroupName, TotalScore = SUM((t.Score * t.GroupPercent) / 100.00)
FROM (
SELECT Score = y.Score,
GroupName = LTRIM(z.XmlCol.value('(item/text())[1]', 'VARCHAR(100)')),
GroupPercent= TRY_CONVERT(NUMERIC(5, 2), REPLACE(LTRIM(z.XmlCol.value('(item/text())[last()]', 'VARCHAR(100)')), '%', ''))
FROM (
SELECT *, SegmentationAsXML = CONVERT(XML, '<row><group><item>' + REPLACE(REPLACE(x.Segmentation, ';', '</item></group><group><item>'), '-', '</item><item>') + '</item></group></row>')
FROM @Table1 x
) y
OUTER APPLY y.SegmentationAsXML.nodes('row/group') z(XmlCol)
) t
GROUP BY t.GroupName
注意#1:我假设源字符串(分段不包含XML保留字符)。
如果源字符串包含XML保留字符,那么您可以测试以下函数:
REPLACE(x.Segmentation, ';',
- &GT;
REPLACE( (SELECT x.Segmentation AS '*' FOR XML PATH('')), '; '
注意#2:它将Segmentation
(s)字符串转换为XML,因此:
'GROUP 1 - SET A - 50%; GROUP 2 - 25%'
变成了
'<row><group><item>GROUP 1</item><item>SET A</item><item>50%</item></group><group><item>GROUP 2</item><item>25%</item>'
注意#3:它使用last()
XQuery函数来访问每个item
内的最后group
。