Dynamic values in where clause - sql

I am trying to read rows one by one from a table and pass values to the query condition. I am unable to proceed further. do I have to use counter /iteration or is there any options. Any help is much appreciated
I want to pass values into the value like condition
create table #temp
(
userid int,
typeid int
)
insert into #temp values (1, 101)
insert into #temp values (1, 221)
insert into #temp values (3, 401)
insert into #temp values (4, 501)
create table #target
(
userid int,
roleid int,
value varchar(max)
)
insert into #target values (1, 000, 'something here userid:1 typeid:101 something here')
insert into #target values (1, 001, 'something here userid:1 typeid:221 something here')
insert into #target values (1, 001, 'something here userid:1 typeid:331 something here')
insert into #target values (3, 002, 'something here userid:3 typeid:401 something here')
select t.userid, d.roleid, t.typeid
from #target d
inner join #temp t on t.userid = d.userid
and value like '%userid:'t.userid' typeid:'t.typeid'%'
This is the result I get:
userid
roleid
typeid
1
000
101
1
001
221
3
002
401

Seems you just need to familiarise yourself with the string concatenation operator:
select t.userid, roleid, typeid
-- How to debug such a query
--, [value]
--,'%userid:' + convert(varchar(32),t.userid) + ' typeid:' + convert(varchar(32),t.typeid) + '%'
--, case when d.[value] like '%userid:' + convert(varchar(32),t.userid) + ' typeid:' + convert(varchar(32),t.typeid) + '%' then 1 else 0 end
from #target d
inner join #temp t on t.userid = d.userid
and d.[value] like '%userid:' + convert(varchar(32),t.userid) + ' typeid:' + convert(varchar(32),t.typeid) + '%'
Returns
userid
roleid
typeid
1
0
101
1
1
221
3
2
401

Related

Sql split comma separated data and check with other table

I have a one table with 2 fields one for tag and another for ProspectID
DECLARE #Filter NVARCHAR(251) ='30,40'
declare #temp table
(
TagID NVARCHAR(MAX),
ProspectID INT
)
INSERT INTO #temp(TAGID,ProspectID)
VALUES
('20,30,40' ,1),
('30,50' ,2),
('20,30,40' ,3),
('60,70' ,4),
('30' ,5)
Need to return 30 contains prospectID and 40 contains as per my example
Output I need
ProspectID
1
3
5
This is a question of Relational Division With Remainder, of which there are many solutions. I will present one common one.
You can use STRING_SPLIT to break up your values:
declare #temp table
(
TagID NVARCHAR(MAX),
ProspectID INT
)
INSERT INTO #temp(TAGID,ProspectID)
VALUES
('20,30,40' ,1),
('30,50' ,2),
('20,30,40' ,3),
('60,70' ,4),
('30' ,5)
DECLARE #Filter NVARCHAR(251) ='30,40'
SELECT
t.ProspectID
FROM #temp t
WHERE EXISTS (SELECT 1
FROM STRING_SPLIT(#Filter, ',') f
LEFT JOIN STRING_SPLIT(t.TagID, ',') t ON t.value = f.value
HAVING COUNT(t.value) = COUNT(*) -- none missing
);
db<>fiddle
However, your schema design is flawed. Do not store multiple pieces of information in one column or value. Instead store them in separate rows.
So you would have a table ProspectTag storing each combination (what you get by splitting the strings into separate rows), and #Filter should be a table variable or Table Valued Parameter also.
declare #temp table
(
TagID int,
ProspectID int
);
INSERT INTO #temp (TagID, ProspectID)
VALUES
(20, 1),
(30, 1),
(40, 1),
(30, 2),
(50, 2),
(20, 3),
(30, 3),
(40, 3),
(60, 4),
(70, 4),
(30, 5);
DECLARE #Filter TABLE(value int PRIMARY KEY);
INSERT #Filter (value) VALUES
(30),
(40);
DECLARE #totalFilters int = (SELECT COUNT(*) FROM #Filter);
SELECT
t.ProspectID
FROM #temp t
JOIN #Filter f ON t.TagID = f.value
GROUP BY
t.ProspectID
HAVING COUNT(*) = #totalFilters; -- none missing
db<>fiddle
use follwing query
SELECT ProspectID
FROM #temp
WHERE TAGID LIKE '%' + #Filter + '%'
--WHERE TAGID LIKE '%' + LTRIM(RTRIM(#Filter)) + '%'
or TagID in (PARSENAME(REPLACE(#Filter,',','.'),2) )--for ProspectID=5

Sql Query to display output horizontally

I need to display a query output in a horizontal manner. I have some example data
create table TestTable (id number, name varchar2(10))
insert into TestTable values (1, 'John')
insert into TestTable values (2, 'Mckensy')
insert into TestTable values (3, 'Valneech')
insert into TestTable values (4, 'Zeebra')
select * from TestTable
This gets the output in a vertical view.
ID Name
==========
1 John
2 Mckensy
3 Valneech
4 Zeebra
However, I need to display it horizontally.
ID 1 2 3 4
Name John Mckensy Valneech Zeebra
create table #TestTable (id int, name varchar(10))
insert into #TestTable values (1, 'John')
insert into #TestTable values (2, 'Mckensy')
insert into #TestTable values (3, 'Valneech')
insert into #TestTable values (4, 'Zeebra')
select *
from
(
select *
from #TestTable
) src
pivot
(
max(name)
for id in ([1], [2], [3],[4])
) piv;
output
1 2 3 4
John Mckensy Valneech Zeebra
You can also use dynamic sql query something like below.
Query
declare #sql as varchar(max);
select #sql = 'select ' + char(39) + 'Name' + char(39) + ' Id,' + stuff((
select
',max(case [Id] when ' + cast(id as varchar(10)) + ' then name end) ['
+ cast([Id] as varchar(10)) + ']'
from TestTable
for xml path('')
), 1, 1, '');
select #sql += 'from TestTable;';
exec(#sql);

T-SQL Summation

I'm trying to create result set with 3 columns. Each column coming from the summation of 1 Column of Table A but grouped by different ID's. Here's an overview of what I wanted to do..
Table A
ID Val.1
1 4
1 5
1 6
2 7
2 8
2 9
3 10
3 11
3 12
I wanted to create something like..
ROW SUM.VAL.1 SUM.VAL.2 SUM.VAL.3
1 15 21 33
I understand that I can not get this using UNION, I was thinking of using CTE but not quite sure with the logic.
You need conditional Aggregation
select 1 as Row,
sum(case when ID = 1 then Val.1 end),
sum(case when ID = 2 then Val.1 end),
sum(case when ID = 3 then Val.1 end)
From yourtable
You may need dynamic cross tab or pivot if number of ID's are not static
DECLARE #col_list VARCHAR(8000)= Stuff((SELECT ',sum(case when ID = '+ Cast(ID AS VARCHAR(20))+ ' then [Val.1] end) as [val.'+Cast(ID AS VARCHAR(20))+']'
FROM Yourtable
GROUP BY ID
FOR xml path('')), 1, 1, ''),
#sql VARCHAR(8000)
exec('select 1 as Row,'+#col_list +'from Yourtable')
Live Demo
I think pivoting the data table will yield the desired result.
IF OBJECT_ID('tempdb..#TableA') IS NOT NULL
DROP TABLE #TableA
CREATE TABLE #TableA
(
RowNumber INT,
ID INT,
Value INT
)
INSERT #TableA VALUES (1, 1, 4)
INSERT #TableA VALUES (1, 1, 5)
INSERT #TableA VALUES (1, 1, 6)
INSERT #TableA VALUES (1, 2, 7)
INSERT #TableA VALUES (1, 2, 8)
INSERT #TableA VALUES (1, 2, 9)
INSERT #TableA VALUES (1, 3, 10)
INSERT #TableA VALUES (1, 3, 11)
INSERT #TableA VALUES (1, 3, 12)
-- https://msdn.microsoft.com/en-us/library/ms177410.aspx
SELECT RowNumber, [1] AS Sum1, [2] AS Sum2, [3] AS Sum3
FROM
(
SELECT RowNumber, ID, Value
FROM #TableA
) a
PIVOT
(
SUM(Value)
FOR ID IN ([1], [2], [3])
) AS p
This technique works if the ids you are seeking are constant, otherwise I imagine some dyanmic-sql would work as well if changing ids are needed.
https://msdn.microsoft.com/en-us/library/ms177410.aspx

I have a SQL table with multiple rows that I want into one row with multiple columns

I have a SQL table that has mulitiple rows of data for a user. I want to query that data and return one row for each user. So I want to take the multiple rows and combine them into one row with multiple columns. Is this possible?
Here is what I currently have
UserID Value
8111 396285
8111 812045789854
8111 Secretary
Here is what I am after
UserID Column1 Column2 Column3
8111 396285 812045789854 Secretary
You can use the PIVOT function to get the result. I used the row_number() function to generate the values that will be converted to columns.
If you know how many values you will have ahead of time, then you can hard-code the query:
select userid, Col1, Col2, Col3
from
(
select userid, value,
'Col'+cast(row_number() over(partition by userid
order by (select 1)) as varchar(10)) rn
from yt
) d
pivot
(
max(value)
for rn in (Col1, Col2, Col3)
) piv;
See SQL Fiddle with Demo.
If you have an unknown number of values, then you can use dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME('Col'+cast(row_number() over(partition by userid
order by (select 1)) as varchar(10)))
from yt
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT userid,' + #cols + '
from
(
select userid, value,
''Col''+cast(row_number() over(partition by userid
order by (select 1)) as varchar(10)) rn
from yt
) x
pivot
(
max(value)
for rn in (' + #cols + ')
) p '
execute(#query);
See SQL Fiddle with Demo. Both give the result:
| USERID | COL1 | COL2 | COL3 |
----------------------------------------------
| 8111 | 396285 | 812045789854 | Secretary |
If you cannot or don't want to use PIVOT/UNPIVOT another option would be to join the columns one by one to the users:
DECLARE #Users TABLE(
UserID int NOT NULL
)
INSERT INTO #Users (UserID) VALUES (1)
INSERT INTO #Users (UserID) VALUES (2)
INSERT INTO #Users (UserID) VALUES (3)
DECLARE #AnyTable TABLE(
UserID int NOT NULL,
FieldNo int NOT NULL,
Value varchar(50) NULL
)
INSERT INTO #AnyTable (UserID, FieldNo, Value) VALUES (1, 1, 'abc')
INSERT INTO #AnyTable (UserID, FieldNo, Value) VALUES (1, 2, 'def')
INSERT INTO #AnyTable (UserID, FieldNo, Value) VALUES (1, 3, 'ghi')
INSERT INTO #AnyTable (UserID, FieldNo, Value) VALUES (2, 1, '123')
INSERT INTO #AnyTable (UserID, FieldNo, Value) VALUES (2, 3, '789')
SELECT u.UserID,
col1.Value as Column1,
col2.Value as Column2,
col3.Value as Column3
FROM #Users u
LEFT JOIN #AnyTable col1
ON col1.UserID = u.UserID
AND col1.FieldNo = 1
LEFT JOIN #AnyTable col2
ON col2.UserID = u.UserID
AND col2.FieldNo = 2
LEFT JOIN #AnyTable col3
ON col3.UserID = u.UserID
AND col3.FieldNo = 3
The result would be:
UserID Column1 Column2 Column3
1 abc def ghi
2 123 NULL 789
3 NULL NULL NULL

How do I join an unknown number of rows to another row?

I have this scenario:
Table A:
---------------
ID| SOME_VALUE|
---------------
1 | 123223 |
2 | 1232ff |
---------------
Table B:
------------------
ID | KEY | VALUE |
------------------
23 | 1 | 435 |
24 | 1 | 436 |
------------------
KEY is a reference to to Table A's ID. Can I somehow join these tables so that I get the following result:
Table C
-------------------------
ID| SOME_VALUE| | |
-------------------------
1 | 123223 |435 |436 |
2 | 1232ff | | |
-------------------------
Table C should be able to have any given number of columns depending on how many matching values that are found in Table B.
I hope this enough to explain what I'm after here.
Thanks.
You need to use a Dynamic PIVOT clause in order to do this.
EDIT:
Ok so I've done some playing around and based on the following sample data:
Create Table TableA
(
IDCol int,
SomeValue varchar(50)
)
Create Table TableB
(
IDCol int,
KEYCol int,
Value varchar(50)
)
Insert into TableA
Values (1, '123223')
Insert Into TableA
Values (2,'1232ff')
Insert into TableA
Values (3, '222222')
Insert Into TableB
Values( 23, 1, 435)
Insert Into TableB
Values( 24, 1, 436)
Insert Into TableB
Values( 25, 3, 45)
Insert Into TableB
Values( 26, 3, 46)
Insert Into TableB
Values( 27, 3, 435)
Insert Into TableB
Values( 28, 3, 437)
You can execute the following Dynamic SQL.
declare #sql varchar(max)
declare #pivot_list varchar(max)
declare #pivot_select varchar(max)
Select
#pivot_list = Coalesce(#Pivot_List + ', ','') + '[' + Value +']',
#Pivot_select = Coalesce(#pivot_Select, ', ','') +'IsNull([' + Value +'],'''') as [' + Value + '],'
From
(
Select distinct Value From dbo.TableB
)PivotCodes
Set #Sql = '
;With p as (
Select a.IdCol,
a.SomeValue,
b.Value
From dbo.TableA a
Left Join dbo.TableB b on a.IdCol = b.KeyCol
)
Select IdCol, SomeValue ' + Left(#pivot_select, Len(#Pivot_Select)-1) + '
From p
Pivot ( Max(Value) for Value in (' + #pivot_list + '
)
)as pvt
'
exec (#sql)
This gives you the following output:
Although this works at the moment it would be a nightmare to maintain. I'd recommend trying to achieve these results somewhere else. i.e not in SQL!
Good luck!
As Barry has amply illustrated, it's possible to get multiple columns using a dynamic pivot.
I've got a solution that might get you what you need, except that it puts all of the values into a single VARCHAR column. If you can split those results, then you can get what you need.
This method is a trick in SQL Server 2005 that you can use to form a string out of a column of values.
CREATE TABLE #TableA (
ID INT,
SomeValue VARCHAR(50)
);
CREATE TABLE #TableB (
ID INT,
TableAKEY INT,
BValue VARCHAR(50)
);
INSERT INTO #TableA VALUES (1, '123223');
INSERT INTO #TableA VALUES (2, '1232ff');
INSERT INTO #TableA VALUES (3, '222222');
INSERT INTO #TableB VALUES (23, 1, 435);
INSERT INTO #TableB VALUES (24, 1, 436);
INSERT INTO #TableB VALUES (25, 3, 45);
INSERT INTO #TableB VALUES (26, 3, 46);
INSERT INTO #TableB VALUES (27, 3, 435);
INSERT INTO #TableB VALUES (28, 3, 437);
SELECT
a.ID
,a.SomeValue
,RTRIM(bvals.BValues) AS ValueList
FROM #TableA AS a
OUTER APPLY (
-- This has the effect of concatenating all of
-- the BValues for the given value of a.ID.
SELECT b.BValue + ' ' AS [text()]
FROM #TableB AS b
WHERE a.ID = b.TableAKEY
ORDER BY b.ID
FOR XML PATH('')
) AS bvals (BValues)
ORDER BY a.ID
;
You'll get this as a result:
ID SomeValue ValueList
--- ---------- --------------
1 123223 435 436
2 1232ff NULL
3 222222 45 46 435 437
This looks like something a database shouldn't do. Firstly; a table cannot have arbitrary number of columns depending on whatever you'll store. So you will have to put up a maximum number of values anyway. You can get around this by using comma seperated values as value for that cell (or a similar pivot-like solution).
However; if you do have table A and B; i recommend keeping to those two tables; as they seem to be pretty normalised. Should you need a list of b.value given an input a.some_value, the following sql query gives that list.
select b.value from a,b where b.key=a.id a.some_value='INPUT_VALUE';