SQL IF to Set Parameter Value Within SELECT Statement - sql

EDIT: This problem has been solved using a better method. Rather than using a variable I am concatenating results to get my desired output.
I am trying to get values from several fields from a couple of different tables and that works fine. But I would also like to have a "#Description" which is a concatenation of hard coded text based on existing values for each row.
DECLARE #Description VARCHAR(1000) = ''
SELECT t1.ID
t1.myType
t1.myName
,CASE WHEN
(
t1.aValue1 = 1
AND t1.aValue2 = 1
AND t2.aValue1 = 1
AND t2.aValue2 = 1
)
THEN 'ELIGIBLE'
ELSE 'NOT ELIGIBLE'
END AS 'isEligible'
,#Description
-- Then I'm trying to set the description
/*
IF
(
t1.aValue1 = 2
)
SET #Description = #Description + ' t1.aValue1 is 2'
IF
(
t1.aValue2 = 2
)
SET #Description = #Description + ' t1.aValue2 is 2'
IF
(
t2.aValue1 = 2
)
SET #Description = #Description + ' t2.aValue1 is 2'
IF
(
t2.aValue2 = 2
)
SET #Description = #Description + ' t2.aValue2 is 2'
*/
END AS 'Description'
FROM [dbo].[Table1] t1
JOIN [dbo].[Table2] t2 ON t1.ID = t2.ID
So for example, if a row had a t1.aValue1 = 2 and t2.aValue1 = 2 then the output might look something like this.
ID | myType | myName | isEligible | Description
-----------------------------------------------
...
24 | Red | John | Not Eligible | t1.aValue1 is 2 t2.aValue1 is 2
25 | Blue | Eric | Eligible |
etc...
I am using SSMS 2008 R2.
How would I accomplish this?

You have the variable, but the expected results looks like you actually want it to the row? You can get it to the row just by using case, something like this:
END AS isEligible,
case when t1.aValue1 = 2 then 't1.aValue1 is 2 ' else '' end +
case when t1.aValue2 = 2 then 't1.aValue2 is 2 ' else '' end +
case when t2.aValue1 = 2 then 't2.aValue1 is 2 ' else '' end +
case when t2.aValue2 = 2 then 't2.aValue2 is 2 ' else '' end as Description

Related

Row level security + Switch statement

I've a big table with lot of data who needs to have some RLS security.
The RLS is based on an other table (user logins with a profile number).
I've to make different logic of filtering depending on the profile number...
Let's say if the userProfile is 1 he can see all data.
If the user profile is 2 he can only see the data based on colA if he's 3 it's colB who have to be checked.
Example :
Profile | login Data | colA | colB
2 | toto data | toto | tutu
3 | tutu data | tata | tutu
I've tried to create a Switch statement based on profileType but it doesn't work. And i don't know if we can return a filtering in switch.
My try :
CREATE FUNCTION [dbo].[fn_rls_users](#username AS VARCHAR(50))
RETURNS TABLE
with schemabinding
AS
RETURN (
SELECT Department,ProfileType,
CASE
WHEN ProfileType = 1 THEN
RETURN (
SELECT 1 AS [fn_rls_users]
FROM BIG_TABLE
)
WHEN ProfileType = 2 THEN
RETURN (
SELECT 1 AS [fn_rls_users]
FROM BIG_TABLE
WHERE Department = Department
)
ELSE (
SELECT 0 AS [fn_rls_users]
FROM BIG_TABLE
)
END
FROM dbo.UserProfiles WHERE UserLogin = #username
)
GO
Any help appreciated
DECLARE #ProfileType date = (SELECT ProfileType FROM dbo.UserProfiles WHERE UserLogin = #username)
if #ProfileType = 1
select isnull(Data, 'NaN') from BIG_TABLE
else if #ProfileType = 2
select isnull(Data, 'NaN') from BIG_TABLE where colA = #username
else
select isnull(Data, 'NaN') from BIG_TABLE where colB = #username
End
Or, if you like using str exec
DECLARE #ProfileType date = (SELECT ProfileType FROM dbo.UserProfiles WHERE UserLogin = #username)
declare #str_sql varchar(1000)
set #str_sql = 'select isnull(Data, "NaN") from BIG_TABLE'
if #ProfileType = 2
set #str_sql += ' where colA = ' + #username
else if #ProfileType = 3
set #str_sql += ' where colB = ' + #username
exec(#str_sql)

Fill multiple empty rows

I'm tryting to fill empty rows from my table . Here is the example from my table.
ID | Code |
1 NULL
2 NULL
3 NULL
what i want is
ID | Code |
1 KL0000001
2 KL0000002
3 KL0000003
I'm using sql server 2008 and here is my script so far :
declare #jml as int;
declare #no as int = 1;
declare #kode as varchar(50);
set #jml = (SELECT COUNT(IdArealeader) FROM arealeader);
set #kode = (select case
when right(max(KodeareaLeader),7) is null then 'KL0000001'
else ('KL' + RIGHT('0000000' + cast(right(max(KodeareaLeader),7) + 1 as nvarchar),7))
end KodeareaLeader from arealeader)
while #no < #jml begin
update arealeader set KodeareaLeader = #kode;
END
Try this simple method,
UPDATE T
SET T.Code = 'KL'+REPLICATE('0',7 - LEN(ID))+CAST(ID AS NVARCHAR(10))
FROM test_table T
Try to avoid loops, only use if it necessary.
Result
ID Code
1 KL0000001
2 KL0000002
3 KL0000003
....
10 KL0000010

T-SQL Procedure split and join on sub columns

Not really sure how to explain this so I just start with the example.
Say I have a table like this which can include several rows:
id Type Text
1 Test Failure A=123 B=444 C=43343 Error=4 ErroDes=1
I also have a static Error and ErrorDes table which look like this
Id Code Description
1 1 Error1
2 4 Error4
How can I split up the information from the column into seperate fields and also join in the info from the subtables.
Expected result would be something like this:
Type Field1 FieldA FieldB FieldC Error ErrorDes
Test Failure 123 444 43343 Error4 Error1
I used the same table for joining in the example but this is 2 tables in the db.
So to help with this I have a split function in the database.
And if I first split the Text field on "space" and then on "=" I get everything I need (or atleast all the columns in seperate rows)
cross apply dbo.Split(a.Text, ' ') s
cross apply dbo.Split(s.Value, '=') s2
I get "TokenID" and "Value" field back from the split function.
The output from that looks like this:
TokenID Value TokenID Value
1 Failure 1 Failure
2 A=123 1 A
2 A=123 2 123
3 B=444 1 B
3 B=444 2 444
4 C=43343 1 C
4 C=43343 2 43343
5 Error=4 1 Error
5 Error=4 2 4
6 ErrorDes=1 1 ErrorDes
6 ErrorDes=1 2 1
I hope you understand what I ment and can help me how this can be solved.
you can use something like the folowing UDF function to cross apply
create function udf_ReturnTextSplit(#vText varchar(100))
returns #rt table (
Field1 varchar(100),
FieldA varchar(100),
FieldB varchar(100)
) as begin
declare #st varchar(100) = #vText + ' '
declare #sti varchar(100)
declare #stj varchar(100)
insert into #rt (Field1, FieldA, FieldB) values (null, null, null)
declare #i int = charindex(' ', #st)
while #i > 0 begin
set #sti = SUBSTRING(#st, 1, #i)
set #st = substring(#st, #i + 1, 100)
set #i = CHARINDEX('=', #sti)
if #i > 0 begin
set #stj = substring(#sti, #i + 1, 100)
set #sti = substring(#sti, 1, #i - 1)
if #sti = 'A' update #rt set FieldA = #stj
if #sti = 'B' update #rt set FieldB = #stj
end else begin
update #rt set Field1 = #sti
end
set #i = charindex(' ', #st)
end
return
end
go
select * from dbo.udf_ReturnTextSplit('Failure A=123 B=444 C=43343 Error=4 ErroDes=1')

SQL parse delimited string

I can't find a good way to do this and because of some restrictions it has to be a coded without the use of variables but I can call a function. Anyway, I need to return a result set from a Select query and one of the rows is a pipe delimited string.
So, it will return something like:
id| Name | Message |
---------------------
1 | Some Name | 'Here is my | delimited | message'
And I need it to be
id| Name | Message1 | Message2 | Message3
------------------------------------------------------
1 | Some Name | 'Here is my' | 'delimited' | 'message'
I was thinking of something like Parsename('','|',1), where you can pass in the delimiter instead of it always being a period but I don't know the best way to accomplish that.
EDIT: I've tried variations of this but of course it is very confusing. There could be 4 or more |
SELECT Field1,
Field2 AS Originalvalue,
--1
SUBSTRING(Field2,0,CHARINDEX('|',Field2)) AS Msg1,
--2
LEFT(SUBSTRING(Field2,CHARINDEX('|',Field2)+1 ,LEN(Field2)),CHARINDEX('|',SUBSTRING(Field2,CHARINDEX('|',Field2)+1 ,LEN(Field2)))-1)
AS ExtractedValue
FROM Table1 T1 JOIN Table2 T2
ON T1.Id = T2.Id
WHERE T1.Id = 12
You can write a sql function as follows.
create Function dbo.fn_Parsename(#Message Varchar(1000), #delimiter char(1), #index int )
Returns Varchar(1000)
As
Begin
Declare
#curIndex int = 0,
#pos int = 1,
#prevPos int = 0,
#result varchar(1000)
while #pos > 0
Begin
set #pos = CHARINDEX(#delimiter, #Message, #prevPos);
if(#pos > 0)
begin-- get the chars between the prev position to next delimiter pos
set #result = SUBSTRING(#message, #prevPos, #pos-#prevPos)
end
else
begin--get last delim message
set #result = SUBSTRING(#message, #prevPos, LEN(#message))
end
if(#index = #curIndex)
begin
return #result
end
set #prevPos = #pos + 1
set #curIndex = #curIndex + 1;
end
return ''--not found
End
And you can call it as below:
select dbo.fn_Parsename('Here is my | delimited | message','|', 0)
select dbo.fn_Parsename('Here is my | delimited | message','|', 1)
select dbo.fn_Parsename('Here is my | delimited | message','|', 2)

merge two rows in return query as one

I have a query that returns the people in a certain household, however the individuals show up in to separate rows, what i want to do is merge the two rows into one.
SELECT dbo.households.id, dbo.individuals.firstname, dbo.individuals.lastname
FROM dbo.households INNER JOIN
dbo.individuals ON dbo.households.id = dbo.individuals.householdID
WHERE (dbo.households.id = 10017)
Current results:
ID | First Name | Last Name |
1 | Test | Test1 |
1 | ABC | ABC1 |
Desired results:
ID | First Name | Last Name |ID1| First Name1| Last Name1|
1 | Test | Test1 |1 | ABC | ABC1 |
However if theres 3 people then it would need to merge all 3 and so on
Depending on the response to the question I asked above, below is a simple script that would compile the names into a string and then output the string (I don't have access to the syntax validator now so forgive any errors):
DECLARE
#CNT INT,
#R_MAX INT,
#H_ID INT,
#R_FIRST VARCHAR(250),
#R_LAST VARCHAR(250),
#R_NAMES VARCHAR(MAX)
SET #CNT = 0; --Counter
SET #R_NAMES = 'Names: ';
SELECT #R_MAX = COUNT(*) FROM dbo.individuals a WHERE a.householdID = #H_ID; --Get total number of individuals
PRINT(#R_MAX); --Output # of matching rows
--Loop through table to get individuals
WHILE #CNT < #R_MAX
BEGIN
--Select statement
SELECT * FROM (SELECT
#R_FIRST = b.firstname,
#R_LAST = b.lastname,
ROW_NUMBER() OVER (ORDER BY b.lastname, b.firstname) AS Row
FROM
dbo.households a INNER JOIN
dbo.individuals b ON a.id = b.householdID
WHERE
(a.id = #H_ID)) AS RN WHERE (Row = #CNT);
SET #R_NAMES = #R_NAMES + #R_FIRST + #R_LAST + '; '; --Add individual's name to name string
PRINT(CAST(#CNT AS VARCHAR) + ':' + #R_NAMES);
SET #CNT = #CNT +1; --Increase counter
END
PRINT(#R_NAMES); --Output the individuals
Provided you're using SQL Server 2005 or up, you might be able to use FOR XML PATH('') to concatenate the strings.
This should do what you want without having to do manual loops:
edit: fixed up SQL to actually work (now I have access to SQL)
SELECT households.id,
STUFF(
(
SELECT '; ' + [firstname] + '|' + lastname AS [text()]
FROM individuals
WHERE individuals.householdID = households.id
FOR XML PATH('')
)
, 1, 2, '' ) -- remove the first '; ' from the string
AS [name]
FROM dbo.households
WHERE (households.id = 10017)
This is pretty close to the format of data that you wanted.
it converts the data to XML (without any actual XML markup due to the PATH('')) and then joins it back to the header row.