I have a table called Rule_X_ListType in the following structure
Rue_ID ListType_ID Value
---------------------------
1 2 319
1 2 400
1 5 8150
1 5 1000
1 3 10211
2 2 400
2 6 10211
3 7 10211
3 3 8051
2 2 319
If I will give the input as Rule_ID = 1 and ListType_ID = 2, then I need the output as a string with values :
319,400
Anybody please help out...Thanks in advance...
I do not feel the neccessity for either the CTE or the FOR XML PATH.
This can be accomplished using the much more simple method of COALESCE
DECLARE #List varchar(100)
SELECT
#List = COALESCE(#List + ', ', '') + CAST(Value AS varchar(10))
FROM
Rule_X_ListType
WHERE
Rule_ID = 1 and ListType_ID = 2
SELECT #List
Try this
;WITH CTE AS
(
SELECT * FROM Rule_X_ListType WHERE Rue_ID = 1 AND ListType_ID = 2
)
SELECT STUFF
(
(SELECT ',' + A.Value FROM CTE A ORDER BY A.VALUE FOR XML PATH('')),1,1,''
) AS CSVValues
SELECT DISTINCT T1.Rule_ID,T1.ListType_ID,STUFF(VAL,1,1,'') AS VALUE
FROM Rule_X_ListType T1
CROSS APPLY (SELECT ',' + CONVERT(VARCHAR,Value)
FROM Rule_X_ListType T2
WHERE T1.Rule_ID =T2.Rule_ID and T1.ListType_ID =T2.ListType_ID
FOR XML PATH(''))A(VAL)
WHERE T1.Rule_ID = 1 and T1.ListType_ID = 2
SQL Tips and Tricks in http://sqlbay.blogspot.in/
Related
I have the following table:
GR WORD NO.
1 A 4
2 B 5
3 C 6
1 G 5
2 H 5
3 I 5
I would like to get the following table:
GR 4 5 6
1 1 1 0
2 0 2 0
3 0 1 1
For each GR column value I count the NO. values.
Here's a dynamic solution:
--Sample data
--CREATE TABLE tbl (GR int, WORD char(1), [NO] int)
--INSERT INTO tbl values
--(1,'A',4),
--(2,'B',5),
--(3,'C',6),
--(1,'G',5),
--(2,'H',5),
--(3,'I',5)
DECLARE #sql NVARCHAR(MAX)
SELECT #sql = '
SELECT *
FROM tbl
PIVOT(
COUNT(WORD) FOR [NO] IN (' +
(SELECT STUFF(
(
SELECT DISTINCT ',' + QUOTENAME(CAST([NO] AS VARCHAR(10)))
FROM tbl
FOR XML PATH('')
)
, 1, 1, ''))
+ ')
) p
'
EXEC sp_executesql #sql
This is a conditional aggregation
select
GR
,[4] = count(case when NO. = 4 then WORD end)
,[5] = count(case when NO. = 5 then WORD end)
,[6] = count(case when NO. = 6 then WORD end)
from YourTable
group by GR
Or a pivot
select *
from YourTable
pivot(
count(WORD) for NO. in ([4],[5],[6])
) p
This is table A
Wallet Type State
------------------------
106 1
106 2
106 1
106 1
106 2
112 1
112 2
112 2
Now i need a table where it counts wallet type according to the state
Table B would be like this
State Distributor(106) Agent(112)
----------------------------------------
1 3 1
2 2 2
Try this:
You can get this using Aggregate functions.
SUM:
SELECT State
,SUM(CASE WHEN Wallet_Type = 106 THEN 1 ELSE 0 END) Distributor_106
,SUM(CASE WHEN Wallet_Type = 112 THEN 1 ELSE 0 END) Distributor_112
FROM Your_Table
WHERE Wallet_Type IN (106, 112)
GROUP BY State
COUNT:
SELECT State
,COUNT(CASE WHEN Wallet_Type = 106 THEN 1 END) Distributor_106
,COUNT(CASE WHEN Wallet_Type = 112 THEN 1 END) Distributor_112
FROM Your_Table
WHERE Wallet_Type IN (106, 112)
GROUP BY State
These type of problems can also be solved using PIVOT keyword in SQL server.
To know more about PIVOT read here.
see working demo
Your query using PIVOT should be like
select
[state],
[Distributor(106)]=[106],
[Agent(112)]=[112]
from
(
select
[state],
[cstate]=state, -- created duplicate as this will be consumed in count operation and will not be available as output column later
[Wallet Type]
from tableA
) src
pivot
(
count(cstate) for [Wallet Type] in ([106],[112])
)p
You can use pivot table for this case
declare #t1 table (wallet_type int, state int)
insert into #t1
values (106, 1),
(106 , 2 ),
(106 , 1 ),
(106 , 1 ),
(106 , 2 ),
(112 , 1 ),
(112 , 2 ),
(112 , 2 )
--select * from #t1
select *
from
(
select state, wallet_type, count(wallet_type) 'count' from #t1
group by state, wallet_type
) src
pivot
(
sum(count)
for wallet_type in ([106], [112])
) piv;
Online Demo: http://rextester.com/QBTOQ8569
Try this one... (Dynamic PIVOT)
DECLARE #cols AS NVARCHAR(max) = Stuff((SELECT DISTINCT ', ' + Quotename(WalletType)
FROM TableName
FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
DECLARE #query AS NVARCHAR(max) = ' SELECT *
FROM TableName
PIVOT ( Count(wallettype)
FOR wallettype IN ('+#cols+') ) pvt';
EXECUTE(#query)
Output
+-------+-----+-----+
| State | 106 | 112 |
+-------+-----+-----+
| 1 | 3 | 1 |
| 2 | 2 | 2 |
+-------+-----+-----+
First of All, you need to declare a cols Variable that will give you all the distinct Wallet Types that will be used later in the query:
DECLARE #cols AS NVARCHAR(max) =
Stuff((SELECT DISTINCT ', ' + Convert(nvarchar, WalletType)
FROM [IHC].[dbo].[TABLENAMEHERE]
FOR XML PATH ('')), 1, 2, '')
what it does is, it gets all the distinct comma separated WalletTypes. as XML Path gives you data in XML so we can play with it.
then use PIVOT operator as suggested by some people. here:
select *
from
(
select [state], [WalletType], count([WalletType]) as count FROM [IHC].[dbo].[TABLENAMEHERE]
group by [state], [WalletType]
) SourceTable
pivot
(
sum(count)
for [WalletType] in (#cols)
) piv;
the first part of this query gives you state, WalletType, 'Count of Wallet' Types grouped by state and Wallet Type or say broken w.r.t State and Wallet Type
like this:
state WalletType count
1 106 4
2 106 2
1 112 1
2 112 2
now this 'Count of Wallet' as count is used in PIVOT function to get the SUM of COUNT w.r.t the Wallet Types so it sums the count w.r.t WalletType and gives the final result
make sure you use it in a dynamic query.
I have the following data:
Table 1
Row ID Value Cost
1 1 Priority 1 10,000
2 2 Priority 2 9,000
3 3 Priority 3 8,000
4 4 Priority 4 6,000
Table 2
Row Name Priority Cost
1 Jon 1 10,000
2 Bob 3 8,000
3 Dan 4 7,000
4 Steve 2 9,000
5 Bill 3 8,000
...
I want the table to look like this:
Table 3
Row Name Priotity 1 Priority 2 Priority 3 Priority 4
1 Jon 10,000
2 Bob 8,000
3 Dan 7,000
4 Steve 9,000
5 Bill 8,000
...
How can I create rows from Table 1 as columns, and fill in the output as shown in Table 3.
I am hoping this is not as basic as it sounds, but my SQL is terrible!
you can try this for dynamic pivot table.
DECLARE #columns VARCHAR(8000)
SELECT #columns = COALESCE(#columns + ',[' + cast(Value as varchar) + ']',
'[' + cast(Value as varchar)+ ']')
FROM Table1
GROUP BY Value
DECLARE #query VARCHAR(8000)
SET #query = 'with Priorites as
(select a.Name,b.Value,b.Cost from Table2 a left join Table1 b on a.Priority =b.id)
SELECT *
FROM Priorites
PIVOT
(
MAX(Cost)
FOR [Value]
IN (' + #columns + ')
)
AS p'
EXECUTE(#query)
Here is the link for more details http://www.tsqltutorials.com/pivot.php
Pivot is always useful in this sort of scenario, but if the actual data is as simple as it's in question (like there are only 4 unique Priority and/or only 1 Priority is assigned to a particular user),then you can achieve this task with following query:
select t.row,t.name
(case when t.priority = 1 then t.cost
else ' '
end
) as Priority1,
(case when t.priority = 2 then t.cost
else ' '
end
) as Priority2,
(case when t.priority = 3 then t.cost
else ' '
end
) as Priority3,
(case when t.priority = 4 then t.cost
else ' '
end
) as Priority4
From
(select Row,name,priority,cost
from Table2
group by name) t
group by t.name;
I'm trying to compare two "lists" in same table and get records where customerId exists but storeid doesn't exist for that customerid.
Lists (table definition)
name listid storeid customerid
BaseList 1 10 100
BaseList 1 11 100
BaseList 1 11 102
NewList 2 11 100
NewList 2 12 102
NewList 2 12 103
Query:
SELECT
NewList.*
FROM
Lists NewList
LEFT JOIN
Lists BaseList ON BaseList.customerid = NewList.customerid
WHERE
BaseList.listid = 1
AND NewList.listid = 2
AND NewList.storeid <> BaseList.storeid
AND NOT EXISTS (SELECT 1
FROM Lists c
WHERE BaseList.customerid = c.customerid
AND BaseList.storeid = c.storeid
AND c.listid = 2)
Current result:
NewList 2 11 100
NewList 2 12 102
But i'm expecting to only get the result
NewList 2 12 102
as customerid 100 with storeid 11 exists.
Fiddle
If the table definition contains a column Name (as you said), then the statement below returns your result.
I didn't understand your select statement.
SELECT *
from #table
WHERE NAME = 'NewList'
AND customerID IN (SELECT CustomerID FROM #table WHERE NAME = 'BaseList')
AND storeID NOT IN (SELECT storeID FROM #table WHERE NAME = 'BaseList')
This dynamic pivot will show you all your list values and where else the same combination exists:
I add one more group:
insert into Lists(name, listid, storeid, customerid) values('AnotherNew',3,11,100);
insert into Lists(name, listid, storeid, customerid) values('AnotherNew',3,11,102);
insert into Lists(name, listid, storeid, customerid) values('AnotherNew',3,10,100);
Here's the statement:
EDIT: This new statement is - I think - better as it comes over the distinct combinations of customerid and storeid
DECLARE #listNames VARCHAR(MAX)=
STUFF(
(
SELECT DISTINCT ',[' + name + ']'
FROM Lists
FOR XML PATH('')
),1,1,'');
DECLARE #SqlCmd VARCHAR(MAX)=
'
WITH DistinctCombinations AS
(
SELECT DISTINCT customerid,storeid
FROM Lists AS l
)
SELECT p.*
FROM
(
SELECT DistinctCombinations.*
,OtherExisting.name AS OtherName
,CASE WHEN l.listid IS NULL THEN '''' ELSE ''X'' END AS ExistingValue
FROM DistinctCombinations
LEFT JOIN Lists AS l ON DistinctCombinations.customerid=l.customerid AND DistinctCombinations.storeid=l.storeid
OUTER APPLY
(
SELECT x.name
FROM Lists AS x
WHERE x.customerid=l.customerid
AND x.storeid=l.storeid
) AS OtherExisting
) AS tbl
PIVOT
(
MIN(ExistingValue) FOR OtherName IN (' + #ListNames + ')
) AS p';
EXEC(#SqlCmd);
The result
customerid storeid AnotherNew BaseList NewList
100 10 X X NULL
100 11 X X X
102 11 X X NULL
102 12 NULL NULL X
103 12 NULL NULL X
This is the approach before:
DECLARE #listNames VARCHAR(MAX)=
STUFF(
(
SELECT DISTINCT ',[' + name + ']'
FROM Lists
FOR XML PATH('')
),1,1,'');
DECLARE #SqlCmd VARCHAR(MAX)=
'
WITH DistinctLists AS
(
SELECT DISTINCT listid
FROM Lists AS l
)
SELECT p.*
FROM
(
SELECT l.*
,OtherExisting.name AS OtherName
,CASE WHEN l.listid IS NULL THEN '''' ELSE ''X'' END AS ExistingValue
FROM DistinctLists
INNER JOIN Lists AS l ON DistinctLists.listid= l.listid
CROSS APPLY
(
SELECT x.name
FROM Lists AS x
WHERE x.listid<>l.listid
AND x.customerid=l.customerid
AND x.storeid=l.storeid
) AS OtherExisting
) AS tbl
PIVOT
(
MIN(ExistingValue) FOR OtherName IN (' + #ListNames + ')
) AS p';
EXEC(#SqlCmd);
And that is the result:
name listid storeid customerid AnotherNew BaseList NewList
AnotherNew 3 10 100 NULL X NULL
AnotherNew 3 11 100 NULL X X
AnotherNew 3 11 102 NULL X NULL
BaseList 1 10 100 X NULL NULL
BaseList 1 11 100 X NULL X
BaseList 1 11 102 X NULL NULL
NewList 2 11 100 X X NULL
Tested this in Fiddle. Please test it with some more data. But for your input it seems to be working correctly.
SQLFiddle Demo
SELECT c.*
FROM (
SELECT n.*
FROM (
SELECT *
FROM lists
WHERE NAME = 'NewList'
) n
LEFT JOIN (
SELECT *
FROM lists
WHERE NAME = 'BaseList'
) b ON b.storeid = n.storeid
WHERE b.listid IS NULL
) c
WHERE c.customerid IN (
SELECT DISTINCT customerid
FROM lists
WHERE NAME = 'BaseList'
)
I have a view vw_XC_DocInfo_1 with columns VId,VName,DocId,Amount,INum. Below is the table data.
Vid VName DocId Amount INum
1 ABC 10 100 INV1
1 ABC 11 10 INV2
1 ABC 12 20 INV3
1 ABC 13 30 INV4
2 XYZ 14 200 INV5
2 XYZ 15 10 INV6
2 XYZ 16 20 INV7
2 XYZ 17 30 INV8
I need to display output like below.
Vid VName DocIdsList Amount INumList
1 ABC 10,11 110 INV1,INV2
1 ABC 12,13 50 INV3,INV4
2 XYZ 14,15 210 INV5,INV6
3 XYZ 16,17 50 INV7,INV8
I have tried different ways but unable to include aggregate function with STUFF function, please find the query I have tired.
with CTE
as (
select top 20 V.VendorId,
V.VendorName,
STUFF((
select top 3 ',' + CONVERT(varchar(MAX), V1.DocumentId)
from vw_XC_DocInfo_1 V1
where V1.VendorID = V.VendorId
order by V1.DocumentId
for xml PATH('')
), 1, 1, '') as DocIdsList,
STUFF((
select top 3 ',' + CONVERT(varchar(MAX), V1.InvoiceNumber)
from vw_XC_DocInfo_1 V1
where V1.VendorID = V.VendorId
order by V1.InvoiceNumber
for xml PATH('')
), 1, 1, '') as InvNumList
from vw_XC_DocInfo_1 V
order by V.VendorID
)
select VendorId,
VendorName,
DocIdsList,
InvNumList
from CTE
group by VendorId,
VendorName,
DocIdsList,
InvNumList
How about something slightly more outside the box?
SELECT VendorId, VendorName,
CASE WHEN COUNT(DocumentId)>1
THEN CAST(MIN(DocumentId) AS VARCHAR(MAX)) + ',' +
CAST(MAX(DocumentId) AS VARCHAR(MAX))
ELSE CAST(MIN(DocumentId) AS VARCHAR(MAX))
END AS DocIdList,
SUM(Amount) Amount,
CASE WHEN COUNT(InvoiceNumber)>1
THEN MIN(InvoiceNumber) + ',' + MAX(InvoiceNumber)
ELSE MIN(InvoiceNumber)
END AS INumList
FROM
(SELECT *,(ROW_NUMBER() OVER (PARTITION BY VendorId
ORDER BY VendorId) - 1) / 2 AS seq
FROM vw_XC_DocInfo_1) AS result
GROUP BY VendorId, VendorName, seq
Demo here.
Would that work for you?
SELECT V.VendorId,
V.VendorName,
STUFF((
select ',' + CONVERT(varchar(MAX), V1.DocumentId)
from vw_XC_DocInfo_1 V1
where V1.VendorID = V.VendorId
order by V1.DocumentId
for xml PATH('')
), 1, 1, '') as DocIdsList,
SUM(V.Amount) as AmountSums,
STUFF((
select ',' + CONVERT(varchar(MAX), V1.InvoiceNumber)
from vw_XC_DocInfo_1 V1
where V1.VendorID = V.VendorId
order by V1.InvoiceNumber
for xml PATH('')
), 1, 1, '') as InvNumList
FROM vw_XC_DocInfo_1 V
GROUP BY V.VendorId, V.VendorName
ORDER BY V.VendorId, V.VendorName
sorry I had many mistakes in my typing...I think I got it thanks to Joachim Isaksson
you could look at coalesce -
http://www.mssqltips.com/sqlservertip/1521/the-many-uses-of-coalesce-in-sql-server/
but after a brief hunt - I think the question here will help more: Concatenate many rows into a single text string?
Look at the answer by Ritesh that uses XML_Path
;with a
as
(
select Vid,VName,DocId,Amount,INum,
row_number() over(partition by vid order by Inum) n
from vw_XC_DocInfo_1
)
select a.Vid, a.vname,
cast(a.docid as varchar(3)) + coalesce(','+cast(b.docid as varchar(9)), '') docid,
a.amount + coalesce(b.amount, 0) amount,
a.INum + coalesce(',' + b.INum, '') INumList
from a left join a b on a.n + 1 = b.n and a.vid = b.vid
where a.n%2 = 1