I'm trying to build comma separated list per group in sql,
As am using Parallel Data Warehouse i need to do this without using FOR XML or recursive function ( not supported ).
any other way to achieve this ?
Input:
ID Value
1 2
1 3
1 4
2 1
2 10
Output:
ID List
1 2,3,4
2 1,10
This will not perform well at all so I recommend you use some other solution (like a SQL Server linked server to PDW) if you need performance. But I believe this should work on PDW:
declare #ID int = (select min(ID) from tbl);
declare #Value int = -1;
declare #concat varchar(8000) = '';
create table #tmp (
ID int,
[concat] varchar(8000)
)
with (distribution=hash(ID), location=user_db);
while #ID is not null
begin
set #Value = (select min([Value]) from tbl where ID = #ID and [Value]>#Value);
if #Value is not null
set #concat = #concat + case when #concat = '' then '' else ',' end + cast(#Value as varchar(8000));
else
begin
insert #tmp (ID, [concat])
values (#ID, #concat);
set #ID = (select min(ID) from tbl where ID > #ID);
set #Value = -1;
set #concat = '';
end
end
select * from #tmp;
drop table #tmp;
Related
I have select query which returns
id ,name ,description ,price
Im trying to get id,price alone based on condition it should display name ,description
#show =1
select id ,name,if #show = 1 begin name ,description, end ,price from tbl
Thanks
#show =1
if #show = 1
begin
select id, name, description, price from tbl
end
else begin
select id, price from tbl
end
You can join the columns you want and execute the query.
DECLARE #filter AS Integer
DECLARE #columns AS nvarchar(50)
DECLARE #sql AS nvarchar(50)
Set #filter = 1
if #filter = 0
begin
Set #columns = 'id, name, description, price'
end
else begin
Set #columns = 'id, name'
end
set #sql = 'select ' + #columns + ' from tbl'
EXECUTE sp_executesql #sql
print #sql
Based on your comment
i pass show parameter as 0 or 1,if 0 only have to select id , price if i pass 1 it select all 4 column
CREATE PROCEDURE MyProc
#Show BIT = 1 --i pass show parameter as 0 or 1 That means BIT Datatype(True/False)
AS
IF #Show = 0
SELECT ID, Price --if 0 only have to select id , price
FROM Table
ELSE
SELECT * --if i pass 1 it select all 4 column
FROM Table
Your all answer helped me a lot,thanks.
finally i went this method works on string concat
fields are id,name,description,price
declare #id int;
declare #sqlcommand nvarchar(max) ;
declare #visible int ;
set #sqlcommand = 'select id ,'+case when #visible = 1 then 'name ,description' else '' end +',price from tbl
where id = #id'
execute sp_executesql #sqlCommand ,N'#id int',#id=#id
if i pass visible = 1
result will be
id name desc price
visible = 0
id price
Thanks
so I have this currently
SET #title = (SELECT title FROM fnBorrowerBooks(#name, 'G3'))
SET #dateBorrowed = (SELECT DateBorrowed FROM fnBorrowerBooks(#name, 'G3'))
SET #dateReturned = (SELECT DateReturned FROM fnBorrowerBooks(#name, 'G3'))
but basically what I would need is something like
SET #variable 1 = (SELECT * FROM fnBorrowerBooks(#name, #Genre)
But this returns 3 columns and CAN return multiple ROWS which obviously won't work because you can't assign multiple values, I need to print how many results I get so if I get 3 different results I need to print all 3 as in 1 string if that makes sense so
PRINT CONCAT(#variable1, ' ble ble ble') should return me multiple lines depending on how many results there are, and I was unable to find a way on how to achieve this.
If you only need the titles then you can concatenate within your query:
DECLARE #Title NVARCHAR(3000)
SELECT
#Title = COALESCE(#Title + ', ', '') + title
FROM
dbo.fnBorrowerBooks(#name, #genre)
SELECT #title
You could try using a temp table and a loop, like this:
CREATE TABLE #t
(tKey int IDENTITY(1,1) PRIMARY KEY,
Column1 varchar(100),
Column2 varchar(100),
...)
INSERT INTO #t
SELECT * --the columns you select here need to be in the column list above
FROM fnBorrowerBooks(#name, #Genre)
DECLARE #Count int
DECLARE #MyString varchar(max)
SET #Count = 1
SET #MyString = ''
WHILE #Count <= (SELECT MAX(Key) FROM #t)
BEGIN
SET #MyString += (SELECT Column1 + ', ' + Column2 + ... FROM #t WHERE tKey = #Count)
SET #Count += 1
END
PRINT(#MyString)
I have a scenario where i have to Apply filter based on the user selection and Filter should match all the values.
Ex: If user apply the filter for Hotel Amenities it should filter hotel that match all the Amenities selected by User.
HotelID AmenitiesID
1 1
1 2
1 3
2 1
2 4
3 2
3 3
Create PROCEDURE [dbo].[usp_GetHotelListing]
#HotelID INT = 1,
#Amenities varchar(50) = '1,3'
AS
BEGIN
select * from DTHotelAmenities where HotelID = #HotelID and <Searching For Condition>
END
Dynamic query version:
Create PROCEDURE [dbo].[usp_GetHotelListing]
#HotelID INT = 1,
#Amenities varchar(50) = '1,3'
AS
BEGIN
declare #sql nvarchar(max) =
'select * from DTHotelAmenities where HotelID = ' +
cast(#HotelID as nvarchar(max)) +
' and AmenitiesID in(' + #Amenities + ')'
exec(#sql)
END
In general beware of possibility of sql injection threat. You may want to look at sp_executesql alternative.
Maybe something like....
Create PROCEDURE [dbo].[usp_GetHotelListing]
#HotelID INT = 1,
#Amenities varchar(50) = '1,3'
AS
BEGIN
SET NOCOUNT ON;
Declare #xml XML;
Declare #t table (ID INT);
SET #xml = '<root><x>' + REPLACE(#Amenities , ',' , '</x><x>') + '</x></root>'
INSERT INTO #t(ID)
Select r.value('.', 'VARCHAR(max)') value
FROM #xml.nodes('//root/x') as records(r)
select o.*
from DTHotelAmenities o
INNER JOIN #t t ON t.ID = o.AmenitiesID
where o.HotelID = #HotelID
END
COMMSTR1-NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C
I want to seperate the above string as (Required Output)
col1 col2 col3 col4 col5 col6
COMMSTR1 NAC-NAM-P-C FCPANAM1 NAC-NAM-P-C CHAZEL1 NAT-CBM-P-C
I've tried this.
SELECT Contact_assg_list_src,
Contact_Assg_List_Src =
(
case WHEN Contact_Assg_List_Src IS NOT NULL and Contact_Assg_List_Src <> ''
then left(Contact_Assg_List_Src,patindex('%[-]%',Contact_Assg_List_Src)-1)
ELSE Contact_Assg_List_Src
END),
(case WHEN Contact_Assg_List_Src IS NOT NULL and Contact_Assg_List_Src <> ''
then substring(Contact_Assg_List_Src,(Patindex('%[-]%',Contact_Assg_List_Src + ' ')-1),len(Contact_Assg_List_Src))
ELSE Contact_Assg_List_Src
END)
from dbo.FBMSRAW;
Which gives me output like
col1 col2
COMMSTR1 NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C
How can I check whether the string has space then separate the string based on that to
get required output?
If you want to do it efficiently in SQL server, I'd advise using a CLR function.
But if you have to do it in T-SQL, this function will achieve it (slowly, and in an increasingly inefficient way)
create function SplitString
(
#splitchar char(1),
#string varchar(500),
#index int
)
returns varchar(500)
as
begin
declare #split int, #start int, #loop bit, #i int, #ret varchar(500)
select #start = 0, #i = 0
select #split = charindex(#splitchar, #string, 0)
if #index>0
select #loop = 1
else
select #loop = 0
while #loop = 1
begin
select #start = #split+1
select #split = charindex(#splitchar, #string, #start+1)
if #split = 0
begin
select #split = len(#string)+1
end
select #i = #i + 1
if #i = #index
begin
select #loop = 0
end
end
if #split>#start
select #ret = substring(#string, #start, #split-#start)
else
select #ret = null
return #ret
end
select dbo.SplitString (' ', 'COMMSTR1-NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C', [0 based column number])
I have wrote the following script to suit your needs, but your self you need to add some more logic, understand the following script
Create a dummy table
CREATE TABLE TBL_TEMPSTRINGS(STRCOL VARCHAR(200),COL1 VARCHAR(50),
COL2 VARCHAR(50),COL3 VARCHAR(50))
Insert values from your table
INSERT INTO TBL_TEMPSTRINGS
SELECT Contact_assg_list_src From dbo.FBMSRAW
Create a stored procedure to update your dummy table columns, it takes your table name in a string(why you can replace your dummy table with temp table name if you have used)
CREATE PROC SP_SPLITWRODS(#TABLENAME VARCHAR(50),#COLCOUNT INT)
AS
BEGIN
DECLARE #QRY VARCHAR(500)
CREATE TABLE #TBL_TEMP(STRCOL VARCHAR(200))
DECLARE #STRCOL VARCHAR(200)
DECLARE #CURRINDEX INT
DECLARE #TEMP INT
DECLARE #COLINDEX INT
DECLARE #ROWID INT
DECLARE #STRLEN INT
DECLARE #TEMPVALUE VARCHAR(50)
DECLARE #LASTWORD BIT
--CURSOR FOR YOUR TEMP TABLE
DECLARE CUR_TEMP CURSOR LOCAL FOR SELECT STRCOL FROM #TBL_TEMP
--CONSTRUCT QRY FOR FILLING YOUR TABLE
SET #QRY='INSERT INTO #TBL_TEMP SELECT STRCOL FROM ' + #TABLENAME
--FILL TABLE
EXECUTE(#QRY)
OPEN CUR_TEMP
FETCH CUR_TEMP INTO #STRCOL
WHILE ##FETCH_STATUS = 0
BEGIN
SET #CURRINDEX=1
SET #COLINDEX=1
SET #LASTWORD=0
--GET ' ' INDEX
SET #TEMP=CHARINDEX(' ',#STRCOL,#CURRINDEX)
WHILE #TEMP > 0
BEGIN
--YOU WILL GET THE VALUE SEPERATED BY SPACE
SET #TEMPVALUE=SUBSTRING(#STRCOL,#CURRINDEX,#TEMP-#CURRINDEX)
--ADD MORE LOGIC TO UPDATE YOUR COLUMNS (YOUR EXTRA COLUMNS)
--CONTRUCT QRY TO UPDATE CORRESPONDING COL IN YOUR TABLE FOR THE ROW FETCHED
--THIS UPDATES ALL ROWS, YOU NEED TO ADD ONE WHERE CONDITION TO UPDATE THE ROW
SET #QRY='UPDATE ' + #TABLENAME + ' SET COL' + CAST(#COLINDEX AS VARCHAR) + '=''' + #TEMPVALUE + ''''
EXEC(#QRY)
--INCREMENT COL INDEX AFTER UPDATE OF LAST COLUMN
SET #COLINDEX=#COLINDEX+1
SET #CURRINDEX=#TEMP+1
SET #TEMP=CHARINDEX(' ',#STRCOL,#CURRINDEX)
IF #TEMP=0 AND #LASTWORD=0
BEGIN
SET #TEMP=LEN(#STRCOL)+1
SET #LASTWORD=1
END
END
FETCH CUR_TEMP INTO #STRCOL
END
CLOSE CUR_TEMP
DEALLOCATE CUR_TEMP
END
Execute your proc
EXEC SP_SPLITWRODS 'TBL_TEMPSTRINGS',1
See your updated dummy table
SELECT * FROM TBL_TEMPSTRINGS
Presently it is updates 3 columns split by the space, you need to add your own logic to update the columns based on the string you have received(seperated by space).
Hope it helps
First a function to split the text
create function [dbo].[f_split]
(
#param nvarchar(max),
#delimiter char(1)
)
returns #t table (val nvarchar(max), seq int)
as
begin
set #param += #delimiter
;with a as
(
select cast(1 as bigint) f, charindex(#delimiter, #param) t, 1 seq
union all
select t + 1, charindex(#delimiter, #param, t + 1), seq + 1
from a
where charindex(#delimiter, #param, t + 1) > 0
)
insert #t
select substring(#param, f, t - f), seq from a
option (maxrecursion 0)
return
end
go
Query to display the result, assuming there are max 6 'words'
declare #t table(txt nvarchar(500))
insert #t values ('COMMSTR1-NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C'),
('t1 t2 t3 t4 t5 t6')
select * from #t t
outer apply
(
select max(case when seq = 1 then val end) col1,
max(case when seq = 2 then val end) col2,
max(case when seq = 3 then val end) col3,
max(case when seq = 4 then val end) col4,
max(case when seq = 5 then val end) col5,
max(case when seq = 6 then val end) col6
from dbo.f_split(t.txt, ' ')
) b
I have a table called dbo.Tbl_ActivityInformations and the data look like
Activityid activitymaxcount Activityusedcount
1 10 9
2 10 7
3 15 15
And another table called Tbl_AttendeeInformations and the data look like
AttendedID AssID ActivityID
13 123456 1,2
14 123457 1,3
In the Tbl_AttendeeInformations table data will be inserted as new row from page and in the ActivityInformations table Activityusedcount column incremented by one for appropriate activityID.
Now I want to check before inserting a row into AttendeeInformations that Activityusedcount < activitymaxcount using ActivityID. If the condition is satisfied then only it will allow to insert otherwise it should rollback. I have function named SplitString to split ActivityID in Tbl_AttendeeInformations.
This is the code for SplitString
create FUNCTION dbo.SplitString(#FormattedString varchar(8000),#Delimitter char(1))
returns #retResults TABLE(Value varchar(8000),Rownumber int)
as
BEGIN
DECLARE #SearchString as varchar(8000)
DECLARE #AssignString as varchar(8000)
DECLARE #Index int
DECLARE #Count int
set #SearchString = #FormattedString
set #AssignString= ''
set #Count = 0
while(len(#SearchString) > 0 )
begin
SET #Index = CHARINDEX(#Delimitter,#SearchString, 0)
set #Count = #Count + 1
if #Index = 0
begin
INSERT INTO #retResults
values( #SearchString,#Count)
set #SearchString = ''
continue
end
set #AssignString = SUBSTRING(#SearchString,1, #Index - 1 )
INSERT INTO #retResults values
(#AssignString,#Count)
SET #SearchString = (select SUBSTRING(#SearchString, #Index + 1, LEN(#SearchString) - #Index ))
end
return
END
Please do help.
Pseudocode to show an idea:
INSERT INTO AttendeeInformations
SELECT act.*
FROM ActivityInformations act
INNER JOIN AttendeeInformations at ON act.ActivityID = at.ActivityID
WHERE act.Activityusedcount < act.activitymaxcount