I'm trying to get a report done within SQL Server that shows each sales campaign that a phone number appears in.
The desired result:
Phonenumber | Area Code | Campaign 1 | Campaign 2 (if applicable) etc...
I have the following code:
with cids as
(
select distinct
a.outbound_cid as [CID],
a.areacode as [AreaCode],
a.campaign_id as [Campaign]
from
vicislave...vicidial_campaign_cid_areacodes a
join
LDS_SALES_CAMPAIGNS b on a.campaign_id = b.campaign_id
)
select *
from cids
order by cid
Which returns this result (data example):
In this example, I would get
2012444340 201 ZEPTR ZEACC ZBEASTC ZEPRR InBnd2 ZEPSC ZEJCC ZEJSC ZEPCC ZEASC
I've not worked with cross-tabbing before, but it appears to be something that may work, but I have not been able to make it work like I can. Obviously, I can do the MIN and MAX of each of these, but I don't know of a way to get the data into the one row, even using things like Excel, without manually doing it, which with 1110 results with these, I don't really have time to do it.
Not to ape the help that I got from below, here is the exact code that worked:
select distinct
a.outbound_cid as [CID],
a.areacode as [AreaCode],
a.campaign_id as [Campaign]
into
#CIDs
from
vicislave...vicidial_campaign_cid_areacodes a
join
LDS_SALES_CAMPAIGNS b on a.campaign_id = b.campaign_id
select distinct
CID,
areacode,
Campaign = stuff((select ', ' + c2.campaign
from #CIDs c2
where c2.CID = c.CID
for xml path(''), type).value('.', 'nvarchar(MAX)'), 1, 1, '')
from
#cids c
drop table #CIDs
If you use SQL server, you can use STUFF function. You can follow my sample. Hope to help, my friend!
Create table Test(CID nvarchar(10)
, AreaCode nvarchar(10)
, Campaign nvarchar(10))
Insert into Test(CID, AreaCode, Campaign)
values('2012', '201', 'ABC')
Insert into Test(CID, AreaCode, Campaign)
values('2012', '201', 'XYZ')
Insert into Test(CID, AreaCode, Campaign)
values('2014', '201', 'aaa')
Insert into Test(CID, AreaCode, Campaign)
values('2014', '201', 'bbb')
-----------
SELECT distinct CID
, Campaign = STUFF((
SELECT ',' + t2.Campaign
FROM Test t2
WHERE t.CID = t2.CID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM Test t
ORDER BY t.CID
To obtain a single record from any table "TABLE" with a field "field" you have to do
SELECT ';'+rtrim(field)
FROM TABLE FOR XML PATH('')
Tha will return a single record with all the fields concatenated with ";"
in your case you should do :
select ';'+campaign from cids FOR XML PATH('')
order by cid
of course you can even group by CID Column if you need...
SELECT C.CID, (
select ';'+campaign from cids
where cids.CID=C.CID
FOR XML PATH(''))
from CIDS C
group by CID
that would do the trick
Related
I have multiple phone number, multiple email address, multiple fax address in a contact column. I need a query to get the result like below
Contact Id |Phone |Email |Fax
1 |Phone1, Phone2, Phone3|Email1, Email2,Email3,Email4|Fax1, Fax2
2 |Phone1, Phone2 |Email1, Email2,Email3 |Fax1, Fax2
My Input is like
Value MeansOfCommunicationDescription ContactId
email1#port2.com Email 2
www.1_port2.com Web Site 2
Test Insert Fax 2
Test Insert Web Site 2
Test Insert Web Site 2
Test Insert Web Site 2
Test Insert Web Site 2
Test Insert Web Site 2
Test Insert Web Site 2
test Phone 2
test Phone 2
test Phone 2
Test Insert Web Site 2
Test Insert Email 2
You can use CTE to get your desired results. You can try below query:
;WITH ctePhone
AS (
SELECT DISTINCT ContactId [ID],
STUFF(( SELECT N', ' + Phone
FROM Table1 B
WHERE B.ContactId = A.ContactId
FOR XML PATH(''), TYPE
).value('(.)', 'NVARCHAR(MAX)'), 1, 1, '') [Phone],
STUFF(( SELECT N', ' + Email
FROM Table1 B
WHERE B.ContactId = A.ContactId
FOR XML PATH(''), TYPE
).value('(.)', 'NVARCHAR(MAX)'), 1, 1, '') [Email],
STUFF(( SELECT N', ' + Fax
FROM Table1 B
WHERE B.ContactId = A.ContactId
FOR XML PATH(''), TYPE
).value('(.)', 'NVARCHAR(MAX)'), 1, 1, '') [Fax]
FROM Table1 A
)
SELECT DISTINCT #Table1.ContactId,
ctePhone.Phone,
ctePhone.Email,
ctePhone.Fax
FROM Table1
INNER JOIN ctePhone
ON Table1.ContactId = ctePhone.[ID]
if your DB's version is 2017+,you can use string_agg() function
select ContactId,
string_agg(phone,',') within group (order by phone) as phone,
string_agg(email,',') within group (order by email) as email,
string_agg(fax,',') within group (order by fax) as fax
from tab
group by ContactId
CategoryTable
Code Name
1 Food
2 Non-Food
Existing Table Consists list of category, as for example, I have two only Food and Non-Food
As challenge, I am assigning tenants with category or categories (multiple assignment, as there are tenants which are categorized as food and non-food). I i used to insert Tenant and Code to a new table creating this output
TenantAssignTable
Tenant Code
Tenant1 1,2
Tenant2 1
What I need to do, is to load the TenantAssingTable to gridview consisting the Name of the CategoryCode too like this
Desired Output
Tenant CCode Name
Tenant1 1,2 Food,Non-Food
Tenant2 1 Food
I used inner join in my code, but this is limited as I have a string of combined code in Code column.
Select a.tenant, a.ccode, b.name
from TenantAssignTable a inner join CategoryTable b
on a.CCode = b.code
Is there anyway to achieve this kind of output? I know that this is unusual in SQL coding but this is what is challenge as what the desired output is concerned and needs which is to have a multiple assignment of category to a single tenant.
Thanks in advance!
Think simple;
You can with LIKE and XML PATH
DECLARE #CategoryTable TABLE (Code VARCHAR(50), Name VARCHAR(50))
INSERT INTO #CategoryTable
VALUES
('1', 'Food'),
('2', 'Non-Food')
DECLARE #TenantAssignTable TABLE (Tenant VARCHAR(50), Code VARCHAR(50))
INSERT INTO #TenantAssignTable
VALUES
('Tenant1', '1,2'),
('Tenant2', '1')
SELECT
T.Tenant ,
T.Code,
STUFF(
(SELECT
',' + C.Name
FROM
#CategoryTable C
WHERE
',' + REPLACE(T.Code, ' ', '') + ',' LIKE '%,' + C.Code + ',%'
FOR XML PATH('')
), 1, 1, '') A
FROM
#TenantAssignTable T
Result:
Tenant Code A
--------------- ------------ ---------------
Tenant1 1,2 Food,Non-Food
Tenant2 1 Food
You can use some XML transformations:
DECLARE #x xml
SELECT #x = (
SELECT CAST('<t name="'+a.tenant +'"><a>'+REPLACE(a.code,',','</a><a>') +'</a></t>' as xml)
FROM TenantAssignTable a
FOR XML PATH('')
)
;WITH cte AS (
SELECT t.v.value('../#name','nvarchar(max)') as Tenant,
t.v.value('.','int') as CCode,
ct.Name
FROM #x.nodes('/t/a') as t(v)
INNER JOIN CategoryTable ct
ON ct.Code = t.v.value('.','int')
)
SELECT DISTINCT
c.Tenant,
STUFF((SELECT ','+CAST(CCode as nvarchar(10))
FROM cte
WHERE c.Tenant = Tenant
FOR XML PATH('')
),1,1,'') as CCode,
STUFF((SELECT ','+Name
FROM cte
WHERE c.Tenant = Tenant
FOR XML PATH('')
),1,1,'') as Name
FROM cte c
Output:
Tenant CCode Name
Tenant1 1,2 Food,Non-Food
Tenant2 1 Food
The first part (defining #x variable) will bring your table to this kind of XML:
<t name="Tenant1">
<a>1</a>
<a>2</a>
</t>
<t name="Tenant2">
<a>1</a>
</t>
Then in CTE part we join XML with table of categories. And after all get data from CTE with the help of FOR XML PATH.
Create Function as below which return Table from separated Value
CREATE FUNCTION [dbo].[fnSplit]
(
#String NVARCHAR(4000),
#Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
WITH Split(stpos,endpos)
AS(
SELECT 0 AS stpos, CHARINDEX(#Delimiter,#String) AS endpos
UNION ALL
SELECT endpos+1, CHARINDEX(#Delimiter,#String,endpos+1)
FROM Split
WHERE endpos > 0
)
SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
'Data' = SUBSTRING(#String,stpos,COALESCE(NULLIF(endpos,0),LEN(#String)+1)-stpos)
FROM Split
)
Create Function as below which return comma separated Name
CREATE FUNCTION [dbo].[GetCommaSeperatedCategory]
(
#Codes VARCHAR(50)
)
RETURNS VARCHAR(5000)
AS
BEGIN
-- Declare the return variable here
DECLARE #Categories VARCHAR(5000)
SELECT #Categories= STUFF
(
(SELECT ',' + convert(varchar(10), Name, 120)
FROM Category
WHERE Code IN (SELECT Id FROM [dbo].[fnSplit] (#Codes,',') )
ORDER BY Code
FOR XML PATH (''))
, 1, 1, '')
RETURN #Categories
END
AND Last:
SELECT
Tenant,
Code,
(SELECT [dbo].[GetCommaSeperatedCategory] (Code)) AS Name
FROM TblTenant
I need running Id concatenation just like running balance or total..
Concatenate the previous Ids to current Id row wise just like shown in picture
query is
with relation (Id, [orderSequence])
as
(
select Id,cast(Id as varchar(20))
from [ACChartofAccount]
union all
select p.Id, cast(Cast(r.Id as varchar) + ',' + cast(p.Id as varchar) as varchar(20))
from [ACChartofAccount] p
inner join relation r on p.ParentId = r.Id
)
select Id,orderSequence
from relation
order by orderSequence
You can use below query to get above result.
DECLARE #Table TABLE(ID VARCHAR(10));
INSERT INTO #table(ID) VALUES ('320'),(332),(333),(334),(335);
SELECT mt.ID,
STUFF((
SELECT ', ' + ID
FROM #table t
WHERE t.ID <= mt.ID
FOR XML PATH('')), 1, 2, '') AS oldersequence
FROM #table mt
ORDER BY ID
I have a table say ProjectMaster:
Id ProjectName
1 A
2 B
3 C
another table ProjectMeter
Id ProjectId MeterNumber
1 1 #0001
2 1 #0002
3 1 #0003
4 2 #0004
5 2 #0005
6 3 #0006
I wish to have following output
ProjectName MeterNumbers
A #0001, #0002, #0003
B #0004, #0005
C #0006
I tried this and this, but unable to solve my problem.
I cannot use a table variable.
I have a already written Stored Procedure and it brings data from many joined tables. ProjectMaster also happens to be joined in one of these tables. Now am required to fetch data from ProjectMeter, such that, each row has concatenated ProjectMeter.MeterNumber corresponding to the ProjectId in that column.
right now, I get concatenated list of all meternumbers in all the rows.
I cannot use CURSOR, TABLE variable , Temp TABLE
( I hope still something can be done to my cause)
please help.....
Try this:
SELECT projectname, STUFF((SELECT distinct ', ' + meternumber
from projectmeter m
where p.id = m.projectid
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'') MeterNumbers
from projectmaster p
See SQL Fiddle with Demo
DECLARE #ProjectMaster AS TABLE
(
ID INT IDENTITY(1, 1) ,
ProjectName VARCHAR(2)
)
DECLARE #ProjectMeter AS TABLE
(
ID INT IDENTITY(1, 1) ,
ProjectID INT ,
MeterNumber VARCHAR(50)
)
INSERT INTO #ProjectMaster
( ProjectName )
VALUES ( 'A' )
INSERT INTO #ProjectMeter
( ProjectID, MeterNumber )
VALUES ( 1, '#0001' )
INSERT INTO #ProjectMeter
( ProjectID, MeterNumber )
VALUES ( 1, '#0002' )
SELECT pMaster.ID, STUFF(( SELECT ',' + MeterNumber
FROM #ProjectMeter
FOR
XML PATH('')
), 1, 1, '') AS 'Concat Result'
FROM #ProjectMeter pMeter
INNER JOIN #ProjectMaster pMaster ON pMaster.ID = pMeter.ProjectID
GROUP BY pMaster.ID
I have used table variables here but surely you just need to drop the #'s as I have used the same table names as you have specified? Not sure if this is okay? :)
Also in MS SQL you can do it using recursive query with CTE.
Here is a SQLFiddle demo
;with t1 as (
select t.*,
cast(meternumber as varchar(max)) as m2,
0 as level
from ProjectMeter t
where not exists
(select id
from ProjectMeter l
where l.id<t.id and l.ProjectId=t.ProjectID
)
union all
select b.*,
cast(c.m2+','+b.MeterNumber as varchar(max)) as m2,
c.level+1 as level
from ProjectMeter b
inner join t1 c
on (c.id < b.id) and (b.ProjectID=c.ProjectId)
)
select pm.ProjectName as ProjectName,
t1.m2 as MeterNumbers
from t1
inner join
(select ProjectId,max(level) ml
from t1
group by ProjectId
) t2
on (t1.ProjectId=t2.ProjectID) and (t1.level=t2.ml)
left join ProjectMaster pm
on (t1.ProjectId=pm.Id)
order by t1.ProjectID
Situation: This table holds the relation information between a Documents table and an Users table. Certain Users need to review or approve documents (Type). I would like to have it to where I could get all of the reviewers on one line if needed. So if three users review Document 1, then a row would have 346, 394, 519 as the value, since those are the reviewers
Table: xDocumentsUsers
DocID..UserID....Type...
1........386......approver
1........346......reviewer
1........394......reviewer..
1........519......reviewer..
4........408......reviewer..
5........408......reviewer..
6........408......reviewer..
7........386......approver..
7........111......readdone..
7........346......reviewer..
8........386......approver..
8........346......reviewer..
9........386......approver..
9........346......reviewer..
10.......386......approver..
11.......386......approver..
11......346......reviewer..
12......386......approver..
12......346......reviewer..
13......386......approver..
13......346......reviewer..
14......386......approver..
14......346......reviewer..
15......386......approver
So desired result would be...
DocID..UserID................Type...
1........386....................approver
1........346,394,519......reviewer.
4........408....................reviewer..
5........408....................reviewer..
6........408....................reviewer..
7........386....................approver..
7........111....................readdone..
7........346....................reviewer..
8........386....................approver..
8........346....................reviewer..
9........386....................approver..
9........346....................reviewer..
10......386....................approver..
11......386....................approver..
11......346....................reviewer..
12......386....................approver..
12......346....................reviewer..
13......386....................approver..
13......346....................reviewer..
14......386....................approver..
14......346....................reviewer..
15......386....................approver
The FOR XML PATH is a great solution. You need to be aware, though, that it will convert any special characters in the inner SELECTs result set into their xml equivalent - i.e., & will become & in the XML result set. You can easily revert back to the original character by using the REPLACE function around the inner result set. To borrow from astander's previous example, it would look like (note that the SELECT as the 1st argument to the REPLACE function is enclosed in ():
--Concat
SELECT t.ID,
REPLACE((SELECT tIn.Val + ','
FROM #Table tIn
WHERE tIn.ID = t.ID
FOR XML PATH('')), '&', '&'))
FROM #Table t
GROUP BY t.ID
Have a look at
Emulating MySQL’s GROUP_CONCAT() Function in SQL Server 2005
Is there a way to create a SQL Server function to “join” multiple rows from a subquery into a single delimited field?
A simple example is
DECLARE #Table TABLE(
ID INT,
Val VARCHAR(50)
)
INSERT INTO #Table (ID,Val) SELECT 1, 'A'
INSERT INTO #Table (ID,Val) SELECT 1, 'B'
INSERT INTO #Table (ID,Val) SELECT 1, 'C'
INSERT INTO #Table (ID,Val) SELECT 2, 'B'
INSERT INTO #Table (ID,Val) SELECT 2, 'C'
--Concat
SELECT t.ID,
(
SELECT tIn.Val + ','
FROM #Table tIn
WHERE tIn.ID = t.ID
FOR XML PATH('')
)
FROM #Table t
GROUP BY t.ID
Does this help?
SELECT DocID
, [Type]
, (SELECT CAST(UserID + ', ' AS VARCHAR(MAX))
FROM [xDocumentsUsers]
WHERE (UserID = x1.UserID)
FOR XML PATH ('')
) AS [UserIDs]
FROM [xDocumentsUsers] AS x1