Custom query assistance needed - sql

I have 3 tables: (simplified for this question)
REQUIREMENTS : ID (PK), RequirementDescription
CUSTOMERS : ID (PK), CustomerName
CUSTOMER_REQUIREMENTS (join table): ID (PK), RequirementID (FK to REQUIREMENTS table), CustomerID (FK to CUSTOMERS table), DateCompleted
Question: I need to make a gridview in asp.net that basically shows the requirements on the left, all the customers as column headings and the DateCompleted as the "intersection". How can I do this?
For example:

Try following sql and replace temp tables with your table:
CREATE TABLE #REQUIREMENTS
(
ID INT,
RequirementDescription VARCHAR(100)
)
CREATE TABLE #CUSTOMERS
(
ID INT,
CustomerName VARCHAR(100)
)
CREATE TABLE #CUSTOMER_REQUIREMENTS
(
ID INT,
RequirementID INT,
CustomerID INT,
DateCompleted DATE
)
INSERT INTO #REQUIREMENTS VALUES (1,'Requirement1')
INSERT INTO #REQUIREMENTS VALUES (2,'Requirement2')
INSERT INTO #REQUIREMENTS VALUES (3,'Requirement3')
INSERT INTO #REQUIREMENTS VALUES (4,'Requirement4')
INSERT INTO #CUSTOMERS VALUES (1,'JOHN')
INSERT INTO #CUSTOMERS VALUES (2,'MARY')
INSERT INTO #CUSTOMERS VALUES (3,'BOB')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,1,1,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,2,1,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,1,2,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,2,2,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,3,2,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,4,2,'2-2-2014')
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName= ISNULL(#ColumnName + ',','') + QUOTENAME(CustomerName) FROM (SELECT DISTINCT CustomerName FROM #CUSTOMERS) AS Courses
SET #DynamicPivotQuery =
N'SELECT ReqID, ReqDes, ' + #ColumnName + '
FROM
(
SELECT
TEMP.ReqID,
TEMP.ReqDes,
TEMP.CusName,
CusReq.DateCompleted
FROM
(
SELECT
req.ID as ReqID,
req.RequirementDescription as ReqDes,
cus.ID as CusID,
cus.CustomerName as CusName
FROM
#REQUIREMENTS req,#CUSTOMERS cus
) AS TEMP
LEFT JOIN
#CUSTOMER_REQUIREMENTS as CusReq
ON
TEMP.ReqID = CusReq.RequirementID AND
Temp.CusID = CusReq.CustomerID
) AS TEMP1
PIVOT(MAX(TEMP1.DateCompleted)
FOR CusName IN (' + #ColumnName + ')) AS PVTTable'
EXEC sp_executesql #DynamicPivotQuery
DROP TABLE #CUSTOMER_REQUIREMENTS
DROP TABLE #CUSTOMERS
DROP TABLE #REQUIREMENTS

Related

Concatenate values in sql server and group by another value | ms sql server

I have simple select
select distinct UserName, Company from Users inner join Companies on Users.UserName = Companies.UserFullName
The result of query looks like this:
User1 | Company1
User1 | Company2
User1 | Company3
User1 | Company4
User2 | Company3
User2 | Company6
User2 | Company1
User2 | Company5
I want to concatenate Company values and group it by User. Like this:
User1 | Company1 , Company2 , Company3 , Company4
User2 | Company3 , Company6 , Company1 , Company5
Is it possible thing to do in sql server?
If you are using SQL Server 2017, you can use the new function, STRING_AGG:
SELECT UserName,
STRING_AGG(Company,' , ') WITHIN GROUP (ORDER BY Company) AS Companies
FROM #T1
GROUP BY Username;
Note that you have no ordering in your table, thus the order of 'Company3, Company6, Company1, Company5' cannot be retained for 'User2' unless you have some other column to order by.
The below code snippet would work for you -
CREATE TABLE #t1 (UserName VARCHAR(100), Company VARCHAR(100));
INSERT #t1 values ('User1','Company1');
INSERT #t1 values ('User1','Company2');
INSERT #t1 values ('User1','Company3');
INSERT #t1 values ('User1','Company4');
INSERT #t1 values ('User2','Company3');
INSERT #t1 values ('User2','Company6');
INSERT #t1 values ('User2','Company1');
INSERT #t1 values ('User2','Company5');
GO
select
UserName,
stuff((
select ',' + t.[Company]
from #t1 t
where t.UserName = #t1.UserName
order by t.[Company]
for xml path('')
),1,1,'') as CompanyName
from #t1
group by UserName;
Another solution that doesn't require the clause FOR XML PATH
This solution is a loop based
SET NOCOUNT ON
IF OBJECT_ID ('tempdb..#t1') IS NOT NULL DROP TABLE #T1;
IF OBJECT_ID ('tempdb..#t2') IS NOT NULL DROP TABLE #T2;
CREATE TABLE #t1 (UserName VARCHAR(100), Company VARCHAR(100));
INSERT #t1 values ('User1','Company1');
INSERT #t1 values ('User1','Company2');
INSERT #t1 values ('User1','Company3');
INSERT #t1 values ('User1','Company4');
INSERT #t1 values ('User2','Company3');
INSERT #t1 values ('User2','Company6');
INSERT #t1 values ('User2','Company1');
INSERT #t1 values ('User2','Company5');
GO
DECLARE #Table TABLE (UserName VARCHAR(100), Combined VARCHAR(4000))
DECLARE #i INT = 1
SELECT DENSE_RANK () OVER (ORDER BY UserName) Seq, *
INTO #T2
FROM #t1
WHILE #i <= (SELECT MAX(Seq) FROM #T2)
BEGIN
DECLARE #ConcatedCompany VARCHAR(4000) = ''
SELECT #ConcatedCompany+= ',' + Company
FROM #T2
WHERE Seq = #i
INSERT INTO #Table (UserName , Combined)
SELECT UserName , STUFF(#ConcatedCompany,1,1,'')
FROM #T2
WHERE Seq = #i
GROUP BY UserName
SET #i +=1
END
SELECT *
FROM #Table
UPDATE!!
Larnu's comment regarding the performance is a good point, usually I'd avoid using WHILE loops and think in terms of set based operations
so, here is the solution without a loop and without "FOR XML PATH"
SET NOCOUNT ON
IF OBJECT_ID ('tempdb..#t1') IS NOT NULL DROP TABLE #T1
IF OBJECT_ID ('tempdb..##T2') IS NOT NULL DROP TABLE ##T2
IF OBJECT_ID ('tempdb..##Table') IS NOT NULL DROP TABLE ##Table
CREATE TABLE #t1 (UserName VARCHAR(100), Company VARCHAR(100));
INSERT #t1 values ('User1','Company1');
INSERT #t1 values ('User1','Company2');
INSERT #t1 values ('User1','Company3');
INSERT #t1 values ('User1','Company4');
INSERT #t1 values ('User2','Company3');
INSERT #t1 values ('User2','Company6');
INSERT #t1 values ('User2','Company1');
INSERT #t1 values ('User2','Company5');
GO
CREATE TABLE ##Table (UserName nvarchar(50), Combined nvarchar(4000))
SELECT DENSE_RANK () OVER (ORDER BY UserName) Seq, *
INTO ##T2
FROM #t1
DECLARE #cmd NVARCHAR(MAX) =''
;WITH T2 (Seq) AS
(
SELECT DISTINCT Seq
FROM ##T2
)
SELECT #cmd += 'DECLARE #ConcatedCompany'+CONVERT(VARCHAR(10),Seq)+' NVARCHAR(4000) = ''''
SELECT #ConcatedCompany'+CONVERT(VARCHAR(10),Seq)+' += '','' + Company FROM ##T2 WHERE Seq = '+CONVERT(VARCHAR(10),Seq)+ CHAR(10)+
' INSERT INTO ##Table (UserName, Combined)
SELECT UserName , STUFF(#ConcatedCompany'+CONVERT(VARCHAR(10),Seq)+',1,1,'''')
FROM ##T2 WHERE Seq = '+CONVERT(VARCHAR(10),Seq) + CHAR(10)+
' GROUP BY UserName '+CHAR(10)+
';'
+CHAR(10)
FROM T2
EXEC sp_executesql #Cmd
SELECT UserName , Combined
FROM ##Table
DROP TABLE ##Table
DROP TABLE ##T2

Converting row values separated by comma with inner joins tables query

I would like to convert row values separated by comma with inner joins tables query with other columns are also there.
My query is displaying like below records:
Name ID Services Type
xyz 1 s1 A
xyz 1 s2 A
xyz 1 s3 A
abc 2 s2 B
abc 2 s3 B
I'd like output like below:
Name, ID, Services, Type
xyz 1 s1,s2,s3 A
abc 2 s2,s3 B
Please use below code:
create table #name (name varchar(10), id int ,type varchar(10))
insert into #name values ('XYZ',1,'A')
insert into #name values ('abc',2,'B')
create table #services (id int ,[Services] varchar(10))
insert into #services (1,'s1')
insert into #services (1,'s1')
insert into #services (1,'s2')
insert into #services (1,'s3')
insert into #services (2,'s2')
insert into #services (2,'s3')
select Name, t.ID
, (select s1.[Services] +',' from #Services s1 where s1.id = s.id for xml path('')) AS services
,[TyPe]
from #name t
inner join #services s on s.id = t.id
create table #name ( name varchar(10), id int ,type varchar(10))
insert into #name values ('XYZ',1,'A') insert into #name values ('abc',2,'B')
create table #services ( id int ,[Services] varchar(10))
insert into #services values (1,'s1' )
insert into #services values (1,'s2' )
insert into #services values (1,'s3' )
insert into #services values (2,'s2' )
insert into #services values (2,'s3' )
select * from #name
select * from #services
select Name, t.ID ,
(select s1.[Services] +',' from #Services s1 where s1.id=t.id for xml
path('') ) AS sevices ,[TYPe] from #name t

How to insert keyvalue as a row in table?

I have table variable which contains records in terms of key,value pair of a table. where key is the column of table and value is the value for that column
below is table variable
DECLARE #Table TABLE(
FieldName varchar(100),
FieldValue varchar(max))
insert into #Table values('Title','NewFrom')
insert into #Table values('Points','4')
insert into #Table values('createdby','5')
I have above values in UsersInformation.This is physical table of sql server
has following column.
UserID int autoincrement(identity)
Title nvarchar(100),
Points int,
createdby int
I want that all values of #Table should be as a single row of UserInformation table.
How can be using sql server?
Have not tested but this should work
INSERT INTO UsersInformation (Title, Points, createdby)
SELECT Title, Points, createdby FROM (SELECT FieldName, FieldValue
FROM #Table) AS SourceTable
PIVOT (MAX(FieldValue) FOR FieldName IN ([Points], [Title], [createdby])) AS PivotTable;
Based on your comment you will need to add a key to your source #table
DECLARE #Table TABLE(
id int,
FieldName varchar(100),
FieldValue varchar(max))
insert into #Table values(1,'Title','NewFrom')
insert into #Table values(1,'Points','4')
insert into #Table values(1,'createdby','5')
insert into #Table values(2,'Title','NewFrom2')
insert into #Table values(2,'Points','44')
insert into #Table values(2,'createdby','55')
insert into #Table values(3,'Title','NewFrom3')
insert into #Table values(3,'Points','444')
Then you can run the query:
SELECT [Title], [Points], [createdby]
FROM #Table
PIVOT
(
max(FieldValue) FOR [FieldName] IN ([Title], [Points], [createdby])
) AS P

How to get The QueryString Without EXEC and Print Function

I have other table #table3 where the #qur will be stored and using that #qur i want to retrieve the data.
so it is possible to get data without set all query in other variable and execute this query directly.
this string of #qur not fixed it will different for different person.
and yes i use sql server 2010
CREATE TABLE #Table1
([Name] varchar(5), [DateVal] date, [TimeVal] time, [Item] varchar(5))
;
INSERT INTO #Table1
([Name], [DateVal], [TimeVal], [Item])
VALUES
('Lisa', '2015-04-21', '10:20:06', 'Item1'),
('John', '2015-04-21', '10:25:30', 'Item2'),
('Peter', '2015-03-18', '13:35:32', 'Item3'),
('Ralf', '2015-04-03', '09:26:52', 'Item4')
;
CREATE TABLE #Table2
([ID] int, [Name] varchar(5))
;
INSERT INTO #Table2
([ID],[Name])
VALUES
(1,'Lisa' ),
(2,'John' ),
(3,'Peter'),
(4,'Ralf')
;
DECLARE #qur VARCHAR(2000)='([Item] in (''Item1,Item2'')) and [Name]=''Lisa'') '
SELECT DateVal FROM #Table1
WHERE [Name] in (SELECT [Name] FROM #Table2)
AND #qur
Maybe You can use the query bellow in SQLCMD mode:
:setvar qur "and ([Item] in ('Item1','Item2')) and [Name]='Lisa' "
SELECT DateVal FROM #Table1
WHERE [Name] in (SELECT [Name] FROM #Table2)
$(qur)

Can a Pivot table be used with a unknown number of columns?

If I have a team table with a unknown amount of members, is there a way to make the pivot query dynamic?
create table #t (
team varchar (20), member varchar (20)
)
insert into #t values ('ERP', 'Jack')
insert into #t values ('ERP', 'John')
insert into #t values ('ERP', 'Mary')
insert into #t values ('ERP', 'Tim')
insert into #t values ('CRM', 'Robert')
insert into #t values ('CRM', 'Diana')
select * from #t
select team, [1] as teamMember1, /* 1st select */
[2] as teamMember2, [3] as teamMember3
from
(select team , member, row_number () /* 3rd select */
over (partition by team order by team) as rownum
from #t) a
pivot (max(member) for rownum in ([1], [2], [3])) as pvt
drop table #t
Why yes, yes there is. Here's a script I cooked up years ago for a similar problem that was ultimately solved by giving the user Excel and washing my hands of it. I apologize it's not configured with your example data, but hopefully it's easy to follow.
Hope that helps,
John
--------------START QUERY--------------
-- Example Table
CREATE TABLE #glbTestTable
(
ProviderID INT,
Total INT,
PaymentDate SMALLDATETIME
)
--So the dates insert properly
SET DATEFORMAT dmy
-- Populate Example Table
INSERT INTO #glbTestTable VALUES (232, 12200, '12/01/09')
INSERT INTO #glbTestTable VALUES (456, 10200, '12/01/09')
INSERT INTO #glbTestTable VALUES (563, 11899, '02/03/09')
INSERT INTO #glbTestTable VALUES (221, 5239, '13/04/09')
INSERT INTO #glbTestTable VALUES (987, 7899, '02/03/09')
INSERT INTO #glbTestTable VALUES (1, 1234, '02/08/09')
INSERT INTO #glbTestTable VALUES (2, 4321, '02/07/09')
INSERT INTO #glbTestTable VALUES (3, 5555, '02/06/09')
-- Raw Output
SELECT *
FROM #glbTestTable
-- Build Query for Pivot --
DECLARE #pvtColumns VARCHAR(MAX)
SET #pvtColumns = ''
-- Grab up to the first 1023 "Columns" that we want to use in Pivot Table.
-- Tables can only have 1024 columns at a maximum
SELECT TOP 1023 #pvtColumns = #pvtColumns + '[' + CONVERT(VARCHAR, PaymentDate, 103) + '], '
FROM (SELECT DISTINCT PaymentDate FROM #glbTestTable) t_distFP
-- Create PivotTable Query
DECLARE #myQuery VARCHAR(MAX)
SET #myQuery = '
SELECT ProviderID, ' + LEFT(#pvtColumns, LEN(#pvtColumns) - 1) + '
FROM (SELECT ProviderID, PaymentDate, Total
FROM #glbTestTable) AS SourceTable
PIVOT
(
SUM(Total)
FOR PaymentDate IN (' + LEFT(#pvtColumns, LEN(#pvtColumns) - 1) + ')
) AS PivotTable'
-- Run the Pivot Query
EXEC(#myQuery)
-- Cleanup
DROP TABLE #glbTestTable
---------------END QUERY---------------