I'm trying to pass a value from a table into a variable which I can then use in a query. The problem is that I need the variable to have multiple values, which I've never done before. Below is an example of what I'm trying to do.
CompanyID has multiple values for control number. How would I be able to pass multiple values into the variable? The query I'm using is using Open Query so I can't join to a temp table.
declare #t table( companyid int, control_number int)
insert into #t
values(5555, 777),
(5555, 720),
(5555, 234),
(111, 345),
(111, 356)
select *
from #t
declare #CN int
set #CN = (select control_number from #t where companyid = 5555)
select *
from #table
where control_number IN(#CN)
Instead of setting it into variable you can directly use it IN like this :
declare #t table( companyid int, control_number int)
insert into #t
values(5555, 777),
(5555, 720),
(5555, 234),
(111, 345),
(111, 356)
select *
from #t
select *
from #table
where control_number IN(select control_number from #t where companyid = 5555)
Try this out I haven't able to run this because you haven.t shared schema of #table
Another way to skin the cat. Make your second variable a table variable. Then just join to it.
declare #CN table (cntNbr int)
insert #CN (cntNbr)
select control_number from #t where companyid = 5555;
select t.*
from #t as t
join #CN as c
on c.cntNbr = t.control_number;
Rextester link: https://rextester.com/SCYCX42852
Method 1 (Dynamic SQL):
CREATE TABLE #temp ( companyid INT, control_number INT )
INSERT INTO #temp
VALUES (5555, 777),
(5555, 720),
(5555, 234),
(111, 345),
(111, 356)
SELECT * FROM #temp
DECLARE #controlNum VARCHAR(MAX)
SELECT #controlNum = ISNULL(#controlNum + ', ', '') + CAST(control_number AS VARCHAR) FROM #temp WHERE companyid = 5555
DECLARE #sql NVARCHAR(MAX) = 'SELECT * FROM #temp WHERE control_number IN ( ' + #controlNum + ')'
EXEC sp_executesql #sql
Method 2:
DECLARE #temp TABLE( companyid INT, control_number INT )
INSERT INTO #temp
VALUES (5555, 777),
(5555, 720),
(5555, 234),
(111, 345),
(111, 356)
SELECT * FROM #temp
SELECT * FROM #temp WHERE control_number IN (SELECT control_number FROM #temp WHERE companyid = 5555)
Related
Is there any better way to re-write the below code?
SELECT *
FROM PROFILE
WHERE GRP_NUMBER NOT LIKE '2%' AND GRP_NUMBER NOT LIKE '7%'
SELECT *
FROM PROFILE
WHERE GRP_NUMBER LIKE '[^27]%'
Try below sample
DECLARE #Table TABLE(
Col VARCHAR(50)
)
INSERT INTO #Table SELECT '2ABC'
INSERT INTO #Table SELECT '4Italy2'
INSERT INTO #Table SELECT '3Apple'
INSERT INTO #Table SELECT '234.62'
INSERT INTO #Table SELECT '2:234:43:22'
INSERT INTO #Table SELECT '7'
INSERT INTO #Table SELECT '6425.23'
INSERT INTO #Table SELECT '2'
INSERT INTO #Table SELECT 'Lions'
SELECT * FROM #Table
WHERE Col NOT LIKE '[27]%'
SELECT *
FROM PROFILE
WHERE GRP_NUMBER NOT LIKE '[27]%'
If I have a table with a column named "Ids" and another column named "clients" and I have the following data:
IDs Clients
----------------
1 A
2 B
3 C
4 D
I'm trying to get the IDs for multiple clients without writing a query for each one.
So I am using:
select ids
from table1
where clients in (A,B,E,C)
This returns
1,2,3
But I need to know that E is missing. So I really need
1,2,NULL,3
How can I accomplish this?
You can inline the values
declare #t table (id int, client char(1))
insert into #t values
(1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D');
select *
from #t;
SELECT q.client, t.id
FROM ( values ('A'), ('B'), ('E') ) q(client)
left join #t t
on t.client = q.client;
Don't use plural for columns. A row is singular.
Insert your input to a table and proceed your query as below
declare #tbl table (ids int, clients varchar(10))
insert into #tbl values
(1,'A')
,(2,'B')
,(3,'C')
,(4,'D')
SELECT * FROM #tbl
declare #value table (Val varchar(10))
insert into #value values
('A')
,('B')
,('C')
,('E')
select ids,t1.Val
from #tbl t
RIGHT JOIN #value t1 on t1.Val = t.clients
Alertnate option.
declare #tbl table (ids int, clients varchar(10))
insert into #tbl values
(1,'A')
,(2,'B')
,(3,'C')
,(4,'D')
For SQL Server 2016 and above
Declare #var varchar(50) = 'A,B,C,E'
SELECT ids, t1.value
FROM #tbl t
RIGHT JOIN STRING_SPLIT(#var, ',') t1 on t1.value = t.clients
For lower than SQL Server 2016 use below query. You have to create strparse function. script given below
SELECT ids, t1.Keys
FROM #tbl t
RIGHT JOIN dbo.StrParse (',', #var) t1 on t1.Keys = t.clients
go
Create the function for parsing string to rows
CREATE FUNCTION [dbo].[StrParse]
(#delimiter CHAR(1),
#csv NTEXT)
RETURNS #tbl TABLE(Keys NVARCHAR(255))
AS
BEGIN
DECLARE #len INT
SET #len = Datalength(#csv)
IF NOT #len > 0
RETURN
DECLARE #l INT
DECLARE #m INT
SET #l = 0
SET #m = 0
DECLARE #s VARCHAR(255)
DECLARE #slen INT
WHILE #l <= #len
BEGIN
SET #l = #m + 1--current position
SET #m = Charindex(#delimiter,Substring(#csv,#l + 1,255))
IF #m <> 0
SET #m = #m + #l
--insert #tbl(keys) values(#m)
SELECT #slen = CASE
WHEN #m = 0 THEN 255
ELSE #m - #l
END
IF #slen > 0
BEGIN
SET #s = Substring(#csv,#l,#slen)
INSERT INTO #tbl
(Keys)
SELECT #s
END
SELECT #l = CASE
WHEN #m = 0 THEN #len + 1
ELSE #m + 1
END
END
RETURN
END
Ok, I have been banging my head against the wall for about 20 minutes and I can't seem to figure this one out. I have two tables each with a common field (ID) and what I want to do is to concatenate the values form #T2's UDValue column into #T1's UDValue column
CREATE TABLE #T1(ID INT, UDValue NVARCHAR(50))
CREATE TABLE #T2(ID INT, UDValue NVARCHAR(50))
INSERT INTO #T1(ID)
VALUES(1)
INSERT INTO #T2(ID, UDValue)
VALUES(1, 'Tom')
,(1, 'Dick')
,(1, 'Harry')
,(2, 'Chevy')
,(3, 'Apple')
,(2, 'Ford')
UPDATE #T1
SET UDValue = COALESCE(t1.UDValue, '') + t2.UDValue + ','
FROM
#T1 AS t1
INNER JOIN #T2 AS t2 ON t2.ID = t1.ID
SELECT * FROM #T1
DROP TABLE #T1
DROP TABLE #T2
So what I am looking for is to see my data like this:
ID UDValue
1, Tom,Dick,Harry
2, Chevy,Ford
3, Apple
but this is what I am getting:
ID UDValue
1 Tom,
2 Chevy,
3 Apple,
I want to avoid having to loop through each row but I don't see any alternatives.
you can use stuff with for xml path to concatenate column values
you can use a corelated sub query to get the comma separated values
Also it is not a good idea to store it as comma separated values in the database.
;with cte
as
(
select ID,
stuff((select ','+ T2.UDValue
from #T2 T2
where T2.ID = T1.ID
FOR XML PATH ('')), 1,1,'') as NewValue
from #T1 T1
)
update #T1
set UDValue = cte.NewValue
from cte
join #T1
on cte.ID = #T1.ID
select * from #T1
Concatenating Value in Update:
create table #T (Id int, Value varchar(50), primary key (Id, value));
declare #Id int;
declare #Value varchar(500);
insert into #T
( Id , Value )
values
( 1 , 'Tom' ),
( 1 , 'Dick' ),
( 1 , 'Harry' ),
( 2 , 'Chevy' ),
( 3 , 'Apple' ),
( 2 , 'Ford' );
update #T set
#Value = case when #Id is null or #Id = Id then #Value else null end,
#Value = Value = coalesce(#Value + ', ', '') + Value,
#Id = Id;
select Id, max(Value) from #T group by Id;
drop table #T;
The example works only if "primary key" is defined on the table.
More about "Quirky Update" is in Solving the Running Total and Ordinal Rank Problems
This is what I have come up with so far but I am not sure that it is the most efficient way to do this:
CREATE TABLE #T1(ID INT, UDValue NVARCHAR(50))
CREATE TABLE #T2(ID INT, UDValue NVARCHAR(50))
INSERT INTO #T1(ID)
VALUES(1)
,(2)
,(3)
INSERT INTO #T2(ID, UDValue)
VALUES(1, 'Tom')
,(1, 'Dick')
,(1, 'Harry')
,(2, 'Chevy')
,(3, 'Apple')
,(2, 'Ford')
DECLARE #id INT = 1, #UDValue NVARCHAR(MAX)
WHILE(#ID < 4)
BEGIN
SELECT #UDValue = STUFF((SELECT DISTINCT N',' + UDValue
FROM
#T2
WHERE ID = #ID
ORDER BY N',' + UDValue
FOR XML PATH(''), TYPE
).value(N'.[1]',N'nvarchar(max)'),1,1,'');
UPDATE #T1
SET UDValue = #UDValue
FROM
#T1 AS t1
WHERE
t1.ID = #ID
SELECT #ID += 1
END
SELECT * FROM #T1
DROP TABLE #T1
DROP TABLE #T2
I have a table which has a column in it containing a string of comma separated values (CSV).
e.g. VALUE1, VALUE2, VALUE3
Being passed in as a filter is another set of CSV.
e.g. VALUE2, VALUE3
So in the example above, the query should return any records where any of the filter values are in the CSV column.
Example
declare #table table
(
rownum int,
csv nvarchar(300)
)
insert into #table values (1,'VALUE1, VALUE2, VALUE3')
insert into #table values (2,'VALUE1, VALUE2')
insert into #table values (3,'VALUE1, VALUE3')
insert into #table values (4,'VALUE3, VALUE4')
insert into #table values (5,'VALUE1, VALUE2, VALUE3')
insert into #table values (6,'VALUE3, VALUE4, VALUE2')
insert into #table values (7,'VALUE3')
declare #Filter nvarchar(50)
set #Filter = 'VALUE1,VALUE2'
select * from #table
So in the example above, rows 1, 2, 3, 5 and 6 should be returned by a query as they all contain either VALUE1 or VALUE2.
If I well understood it, this will solve it:
You create a function to do the split:
CREATE FUNCTION [dbo].[ufn_CSVToTable] ( #StringInput VARCHAR(8000), #Delimiter nvarchar(1))
RETURNS #OutputTable TABLE ( [String] VARCHAR(10) )
AS
BEGIN
DECLARE #String VARCHAR(10)
WHILE LEN(#StringInput) > 0
BEGIN
SET #String = LEFT(#StringInput,
ISNULL(NULLIF(CHARINDEX(#Delimiter, #StringInput) - 1, -1),
LEN(#StringInput)))
SET #StringInput = SUBSTRING(#StringInput,
ISNULL(NULLIF(CHARINDEX(#Delimiter, #StringInput), 0),
LEN(#StringInput)) + 1, LEN(#StringInput))
INSERT INTO #OutputTable ( [String] )
VALUES ( #String )
END
RETURN
END
GO
Then you can do this:
declare #table table
(
rownum int,
csv nvarchar(300)
)
insert into #table values (1,'VALUE1, VALUE2, VALUE3')
insert into #table values (2,'VALUE1, VALUE2')
insert into #table values (3,'VALUE1, VALUE3')
insert into #table values (4,'VALUE2, VALUE3')
insert into #table values (5,'VALUE1, VALUE2, VALUE3')
insert into #table values (6,'VALUE3, VALUE1, VALUE2')
insert into #table values (7,'VALUE2, VALUE1')
declare #Filter nvarchar(50)
set #Filter = 'VALUE3,VALUE4'
select * from #table
SELECT * INTO #FilterTable FROM ufn_CSVToTable(#Filter, ',')
SELECT * FROM #FilterTable
select * from #table where EXISTS(SELECT String FROM #FilterTable WHERE csv like '%' + String + '%')
DROP TABLE #FilterTable
I'm considering the description "return any rown containing any of the calues in the filter"
You can use the PatIndex to find out the pattern in the field. Like the Following :
SELECT * FROM #TABLE WHERE PATINDEX('%'+#FILTER+'%',CSV)>0
What about this now? I didn't have used any User defined functions at all.
declare #table table
(
rownum int,
csv nvarchar(300)
)
insert into #table values (1,'VALUE1,VALUE2,VALUE3')
insert into #table values (2,'VALUE1,VALUE2')
insert into #table values (3,'VALUE1,VALUE3')
insert into #table values (4,'VALUE2,VALUE3')
insert into #table values (5,'VALUE1,VALUE2,VALUE3')
insert into #table values (6,'VALUE3,VALUE1,VALUE2')
insert into #table values (7,'VALUE2,VALUE1')
DECLARE #FILTER VARCHAR(50)
DECLARE #IN VARCHAR(MAX)
SET #FILTER='VALUE1,VALUE2'
SET #IN=REPLACE(#FILTER,',','%')
SET #IN='%'+#IN+'%'
SELECT #IN
SELECT * FROM #table WHERE PATINDEX(#IN,RTRIM(LTRIM(CSV))) >0
Try this one -
DECLARE #table TABLE (rownum INT, csv NVARCHAR(300))
INSERT INTO #table
VALUES
(1,'VALUE1, VALUE2, VALUE3')
, (2,'VALUE1, VALUE2')
, (3,'VALUE1, VALUE3')
, (4,'VALUE2, VALUE3')
, (5,'VALUE1, VALUE2, VALUE3')
, (6,'VALUE3, VALUE1, VALUE2')
, (7,'VALUE2, VALUE1')
DECLARE #Filter NVARCHAR(50)
SELECT #Filter = 'VALUE1,VALUE2'
;WITH cte AS
(
SELECT token = SUBSTRING(
t.string
, n.number + 1
, ABS(CHARINDEX(',', t.string, n.number + 1) - n.number - 1))
FROM ( SELECT string = ',' + #Filter ) t
CROSS JOIN [master].dbo.spt_values n
WHERE n.[type] = 'p'
AND n.number <= LEN(t.string)
AND SUBSTRING(t.string, n.number, 1) = ','
)
SELECT DISTINCT rownum, csv
FROM cte
JOIN #table ON PATINDEX('%'+ token +'%', CSV) = 0
I just modified #JoseTeixeira code using STRING_SPLIT function.
declare #table table
(
rownum int,
csv nvarchar(300)
)
insert into #table values (1,'VALUE1, VALUE2, VALUE3')
insert into #table values (2,'VALUE1, VALUE2')
insert into #table values (3,'VALUE1, VALUE3')
insert into #table values (4,'VALUE2, VALUE3')
insert into #table values (5,'VALUE1, VALUE2, VALUE3')
insert into #table values (6,'VALUE3, VALUE1, VALUE2')
insert into #table values (7,'VALUE2, VALUE1')
declare #Filter nvarchar(50)
set #Filter = 'VALUE3,VALUE4'
--select * from #table
select * from #table where EXISTS(SELECT [value] FROM string_split(#Filter, ',')
WHERE csv like '%' + [value] + '%') -- Table with filtered records
I am having one query which returns me following output.
(No of results not same all time, means sometimes it gives 3 category,sometimes 8 category etc..)
CategoryName
Test1
Test2
Test3
Now i want that store procedure should return me these date in comma separated format.
e.g. output string should be like: Test1,Test2,Test3
Can you please tell me how can i achieve this?
this will work for all characters in your data:
set nocount on;
declare #YourTable table (BirthDay datetime, PersonName varchar(20))
insert into #YourTable VALUES ('1-10-2010', 'Joe' )
insert into #YourTable VALUES ('2-10-2010', 'Bob <&>' )
insert into #YourTable VALUES ('2-10-2010', 'Alice')
set nocount off
--Concatenation with FOR XML and eleminating control/encoded character expansion "& < >"
SELECT
p1.BirthDay
,STUFF(
(SELECT
', ' + p2.PersonName
FROM #YourTable p2
WHERE p2.BirthDay=p1.BirthDay
ORDER BY p2.PersonName
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
) AS PersonNames
FROM #YourTable p1
GROUP BY p1.BirthDay
OUTPUT:
BirthDay PersonNames
----------------------- ------------------------
2010-01-10 00:00:00.000 Joe
2010-02-10 00:00:00.000 Alice, Bob <&>
(2 row(s) affected)
Try COALESCE or ISNULL:
DECLARE #returnValue varchar(MAX)
SELECT
#returnValue = COALESCE(#returnValue + ', ', '') + CategoryName
FROM
TableName
Have a look at something like (Full working example)
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,
STUFF((
SELECT ',' + t1.Val
FROM #Table AS t1
WHERE t1.ID = t.ID
FOR XML PATH('')
), 1, 1, '')
FROM #Table t
GROUP BY t.ID
Also, you might find that Googling will provide a lot of answers.
One means:
SELECT STUFF((
SELECT ',' + CategoryName AS [text()]
FROM YourTable
FOR XML PATH('')
), 1, 1, '')
...but watch out for XML entities that will be escaped up - e.g. & => &
Just modify the KM answer in a store procedure
ALTER Procedure [dbo].[Payroll_rptAbsentReport]
#FromDate DateTime,
#ToDate DateTime,
#GFacatoryID UniqueIdentifier
As
Begin
-- Temporary table for Row data seperation
CREATE TABLE TestTable(GEmployeeGenInfoID uniqueidentifier, dtAttendDateTime varchar(max))
INSERT INTO
TestTable(GEmployeeGenInfoID, dtAttendDateTime)
SELECT
Payroll_tblAttendance.GEmployeeGenInfoID
,CONVERT(VARCHAR(max), dtAttendDateTime, 105)dtAttendDateTime
FROM Payroll_tblAttendance
INNER JOIN PIS.dbo.PIS_tblEmployeeGenInfo as EmployeeGenInfo ON Payroll_tblAttendance.GEmployeeGenInfoID= EmployeeGenInfo.GEmployeeGenInfoID
WHERE Payroll_tblAttendance.DayStatusID = 0 AND EmployeeGenInfo.GFactoryID=#GFacatoryID AND Payroll_tblAttendance.dtAttendDateTime Between #FromDate and #ToDate ORDER BY dtAttendDateTime
-- Final expected output
SELECT DISTINCT
EmployeeGenInfo.StrEmpName
,EmployeeGenInfo.StrEmpID
,Attendence.CardNo
,EmployeeDesignation.StrDesignationName
,EmployeeDept.StrDepartmentName
-- Count data will be in one column
,(Select COUNT(*) From TestTable Where GEmployeeGenInfoID=Attendence.GEmployeeGenInfoID) TotalAbsent
-- Row data set into one column seperate by coma
,substring( ( SELECT ', ' + dtAttendDateTime as [text()]
FROM TestTable
WHERE GEmployeeGenInfoID = Attendence.GEmployeeGenInfoID
FOR XML path(''), elements
), 3, 1000
) List
FROM
Payroll_tblAttendance as Attendence
INNER JOIN TestTable on TestTable.GEmployeeGenInfoID=Attendence.GEmployeeGenInfoID
INNER JOIN PIS.dbo.PIS_tblEmployeeGenInfo as EmployeeGenInfo ON Attendence.GEmployeeGenInfoID= EmployeeGenInfo.GEmployeeGenInfoID
INNER JOIN PIS.dbo.PIS_tblDesignationInfo as EmployeeDesignation ON EmployeeGenInfo.GDesignationInfoID= EmployeeDesignation.GDesignationInfoID
INNER JOIN PIS.dbo.PIS_tblDepartment as EmployeeDept ON EmployeeGenInfo.GDepartmentID= EmployeeDept.GDepartmentID
WHERE EmployeeGenInfo.GFactoryID=#GFacatoryID AND Attendence.DayStatusID = 0 AND Attendence.dtAttendDateTime Between #FromDate and #ToDate
DROP TABLE TestTable
END