TSQL: Insert Into Table with if condition - sql

I've made a small simple table here:
declare #live bit = 1
declare #temp table(id int, title varchar(30))
insert into #temp (id, title)
select 1, 'myTitle1'
union select 2, 'myTitle2'
union select 3, 'myTitle3'
select * from #temp
Output:
id title
-------------
1 myTitle1
2 myTitle2
3 myTitle3
Now I want the title attribute to be dependent from #live
I'll show it in pseudo-code:
declare #live bit = 1
declare #temp table(id int, title varchar(30))
insert into #temp (id, title)
select 1, IF (#live == 1) THEN 'myTitle1_live' ELSE 'myTitle1'
union select 2, IF (#live == 1) THEN 'myTitle2_live' ELSE 'myTitle2'
union select 3, IF (#live == 1) THEN 'myTitle3_live' ELSE 'myTitle3'
select * from #temp
How would this look in sql syntax?

I think you just want a conditional expression:
select id,
(case when #live = 1 then concat(title, '_live') else title end)
from #temp;
If the data is already in the table, then you would use update:
update t
set #title = concat(title, '_live')
from #temp t
where #live = 1;

Related

Conditionally modify query based on parameter

I have this query (something like a case statement which I can use and fix it)
select *
from mytable
where 1=1
and (isNull(ID, 0) = 0 OR UtilityID IN (9,40))
I also want to add another statement
select *
from mytable
where 1=1
and UtilityID NOT IN (9,40)
Everything is happening in a procedure, so want to use a variable like declare #something so if that is passed as 1, use the first statement and the if 0 is passed, use the latter one.
While I appreciate the genius in Dale's answer I find this more readable:
IF #something = 0
BEGIN
select *
from mytable
where ID IS NULL OR ID = 0 OR UtilityID IN (9,40);
END
IF #something = 1
BEGIN
select *
from mytable
where UtilityID NOT IN (9,40);
END
It's procedure code, so use IF to direct the control flow. Also expanded and simplified your where clauses
I think I understand your logic, ignoring the 1=1 (which does nothing) you want to only allow id = 0 when #something = 1. This should do it:
declare #something bit = 0;
declare #mytable table (ID int, UtilityID int);
insert into #mytable (ID, UtilityID)
select 0, 1 union all
select 1, 2 union all
select 2, 9 union all
select 3, 40;
select *
from #mytable
where (
(#something = 1 and (isnull(ID, 0) = 0 or UtilityID in (9,40)))
or (#something = 0 and (UtilityID not in (9,40)))
);
A more performant approach for a larger query could be:
select *
from #mytable
where (#something = 1 and (isnull(ID, 0) = 0 or UtilityID in (9,40)))
union all
select *
from #mytable
where (#something = 0 and (UtilityID not in (9,40)));
PS: Hopefully your ID cannot ever by null - it should have a constraint on it.

SQL Server: Replace values in field using lookup other table

Let's say I have below table script
DECLARE #result TABLE
(
[ID] Int
,[Data] Varchar(500)
)
DECLARE #codes TABLE
(
[ID] Varchar(500)
,[FullNames] Varchar(500)
)
INSERT INTO #result
SELECT 1
,'[A]-[B]'
INSERT INTO #result
SELECT 2
,'[D]-[A]'
INSERT INTO #result
SELECT 3
,'[A]+[C]'
INSERT INTO #codes
SELECT 'A'
,'10'
INSERT INTO #codes
SELECT 'B'
,'20'
INSERT INTO #codes
SELECT 'C'
,'30'
INSERT INTO #codes
SELECT 'D'
,'40'
SELECT * FROM #result
SELECT * FROM #codes
Output of those are as below:
#result
ID Data
-- -------
1 [A]-[B]
2 [D]-[A]
3 [A]+[C]
#codes
ID FullNames
-- -------
A 10
B 20
C 30
D 40
Now I want output as below also:
ID Data
-- -----
1 10-20
2 40-10
3 10+30
Please help me.
Please note: Data columns also contains ([A]-[B]+[D])*[C]
I found similar solution on https://stackoverflow.com/a/26650255/8454103 which is for your reference.
Try like this;
select Output from (
select Data, c1.FullNames as LeftSideName, c2.FullNames as RightSideName, LeftSide, RightSide, REPLACE(REPLACE(Data,'[' + LeftSide + ']',c1.FullNames),'[' + RightSide + ']',c2.FullNames) as Output from (
select r.ID, Data,SUBSTRING(Data, 2, 1) LeftSide ,SUBSTRING(Data, 6, 1) RightSide from #result r ) Result
inner join #codes c1 ON Result.LeftSide = c1.ID
inner join #codes c2 ON Result.RightSide = c2.ID)
Records
Output:
10-20
10+30
40-10
The query can perform replacing dynamically A,B,C,D,E according to #codes table etc.
Try this:
select ID, REPLACE(REPLACE(REPLACE(REPLACE(Data,
'[A]', (select FullNames from #codes where ID = 'A')),
'[B]', (select FullNames from #codes where ID = 'B')),
'[C]', (select FullNames from #codes where ID = 'C')),
'[D]', (select FullNames from #codes where ID = 'D'))
from #result

How to traverse a path in a table with id & parentId?

Suppose I have a table like:
id | parentId | name
1 NULL A
2 1 B
3 2 C
4 1 E
5 3 E
I am trying to write a scalar function I can call as:
SELECT dbo.GetId('A/B/C/E') which would produce "5" if we use the above reference table. The function would do the following steps:
Find the ID of 'A' which is 1
Find the ID of 'B' whose parent is 'A' (id:1) which would be id:2
Find the ID of 'C' whose parent is 'B' (id:2) which would be id:3
Find the ID of 'E' whose parent is 'C' (id:3) which would be id:5
I was trying to do it with a WHILE loop but it was getting very complicated very fast... Just thinking there must be a simple way to do this.
CTE version is not optimized way to get the hierarchical data. (Refer MSDN Blog)
You should do something like as mentioned below. It's tested for 10 millions of records and is 300 times faster than CTE version :)
Declare #table table(Id int, ParentId int, Name varchar(10))
insert into #table values(1,NULL,'A')
insert into #table values(2,1,'B')
insert into #table values(3,2,'C')
insert into #table values(4,1,'E')
insert into #table values(5,3,'E')
DECLARE #Counter tinyint = 0;
IF OBJECT_ID('TEMPDB..#ITEM') IS NOT NULL
DROP TABLE #ITEM
CREATE TABLE #ITEM
(
ID int not null
,ParentID int
,Name VARCHAR(MAX)
,lvl int not null
,RootID int not null
)
INSERT INTO #ITEM
(ID,lvl,ParentID,Name,RootID)
SELECT Id
,0 AS LVL
,ParentId
,Name
,Id AS RootID
FROM
#table
WHERE
ISNULL(ParentId,-1) = -1
WHILE ##ROWCOUNT > 0
BEGIN
SET #Counter += 1
insert into #ITEM(ID,ParentId,Name,lvl,RootID)
SELECT ci.ID
,ci.ParentId
,ci.Name
,#Counter as cntr
,ch.RootID
FROM
#table AS ci
INNER JOIN
#ITEM AS pr
ON
CI.ParentId=PR.ID
LEFT OUTER JOIN
#ITEM AS ch
ON ch.ID=pr.ID
WHERE
ISNULL(ci.ParentId, -1) > 0
AND PR.lvl = #Counter - 1
END
select * from #ITEM
Here is an example of functional rcte based on your sample data and requirements as I understand them.
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something
(
id int
, parentId int
, name char(1)
)
insert #Something
select 1, NULL, 'A' union all
select 2, 1, 'B' union all
select 3, 2, 'C' union all
select 4, 1, 'E' union all
select 5, 3, 'E'
declare #Root char(1) = 'A';
with MyData as
(
select *
from #Something
where name = #Root
union all
select s.*
from #Something s
join MyData d on d.id = s.parentId
)
select *
from MyData
Note that if you change the value of your variable the output will adjust. I would make this an inline table valued function.
I think I have it based on #SeanLange's recommendation to use a recursive CTE (above in the comments):
CREATE FUNCTION GetID
(
#path VARCHAR(MAX)
)
/* TEST:
SELECT dbo.GetID('A/B/C/E')
*/
RETURNS INT
AS
BEGIN
DECLARE #ID INT;
WITH cte AS (
SELECT p.id ,
p.parentId ,
CAST(p.name AS VARCHAR(MAX)) AS name
FROM tblT p
WHERE parentId IS NULL
UNION ALL
SELECT p.id ,
p.parentId ,
CAST(pcte.name + '/' + p.name AS VARCHAR(MAX)) AS name
FROM dbo.tblT p
INNER JOIN cte pcte ON
pcte.id = p.parentId
)
SELECT #ID = id
FROM cte
WHERE name = #path
RETURN #ID
END

How can I always return 3 values in this stored procedure?

I have an association table. The rows look something like: id, objectID, thingID.
I need a stored procedure to perform a select statement that will return 3 values:
item1ID, item2ID, item3ID
So the query will look something like:
SELECT TOP 3 objectID WHERE thingID = 7 -- (or something)
There may not always be three rows returned, however.
What would the stored proc look like that returned the rows as values, but zeroes for the remaining rows if 3 are not returned?
examples:
data
id: 1, objectID: 12, thingID: 2
id: 2, objectID: 13, thingID: 2
id: 3, objectID: 14, thingID: 3
id: 4, objectID: 15, thingID: 3
id: 5, objectID: 16, thingID: 3
results where thingID = 2
item1ID: 12, item2ID: 13, item3ID: 0
results where thingID = 3
item1ID: 14, item2ID: 15, item3ID: 16
Similar to other answers but using sql table variable instead of temp table.
SQL table variables are cleaned up when the proc completes.
create proc ReturnTop3
as
begin
declare #returnTable as table (
objectId int
)
declare #count int
insert into #returnTable
SELECT TOP 3 objectID WHERE thingID = 7
set #count = (select COUNT(*) from #returnTable)
while (#count < 3)
begin
insert into #returnTable select 0
select #count = #count + 1
end
select * from #returnTable
end
You can create a temp table and do it this way
Create table #test (Id int);
INSERT INTO #test
SELECT TOP 3 objectID WHERE thingID = 7
WHILE (SELECT COUNT(1) from #test) < 3
BEGIN
INSERT INTO #test
VALUES (0)
END
SELECT * FROM #test
DROP TABLE #test
Something like this?
DECLARE #InputThingID INT = 2
DECLARE #ID AS INT, #ItemID1 AS INT = 0, #ItemID2 AS INT = 0, #ItemID3 AS Int = 0
SELECT * INTO #Temp FROM MyTable WHERE ThingID=#InputThingID
SELECT TOP 1 #ID=ID, #ItemID1 = ObjectID FROM #Temp
DELETE FROM #Temp WHERE ID=#ID
SELECT TOP 1 #ID=ID, #ItemID2 = ObjectID FROM #Temp
DELETE FROM #Temp WHERE ID=#ID
SELECT TOP 1 #ID=ID, #ItemID3 = ObjectID FROM #Temp
DELETE FROM #Temp WHERE ID=#ID
SELECT #ItemID1 AS ItemID1, #ItemID2 AS ItemID2, #ItemID3 AS ItemID3
DROP TABLE #Temp
You could do something like this See fiddle
http://sqlfiddle.com/#!3/ed8ca/10
select TOP 3 ID, thing
from
(
select 0 as srt,ID,thing from tbl
where thing = 2
union all
select 1 as srt,0 as ID, 0 as thing
union all
select 2 as srt,0 as ID, 0 as thing
union all
select 3 as srt,0 as ID, 0 as thing
) as t
order by srt,thing
this may be the nicest and most universal, but probably also most difficult solution. The aggregation MAX function is needed, but doesn't affect the result.
SELECT [1] AS Item1ID,[2] AS Item2ID, [3] AS Item3ID FROM
(SELECT ROW_NUMBER()
OVER(order by id) rownum,objectId FROM data where thingId = 3) AS rows
PIVOT(
MAX(objectId)
FOR rownum IN ([1],[2],[3])
) as piv

Problem in string concatenation in sql server using FOR XML Path.

I have the below data
UniqueID ID data
1 1 a
2 1 2
3 1 b
4 1 1
5 2 d
6 2 3
7 2 r
The expected output being
ID ConcatData
1 a,-,-,b,-
2 d,-,-,-,r
What we have to do is that, the number of numeric charecters has to be replaced with those many dashes('-') and then we need to merge the data for the respective id's.
I am using the below query so far
declare #t table(UniqueID int identity(1,1), ID int, data varchar(10))
insert into #t select 1, 'a' union all select 1, '2' union all select 1, 'b'
union all select 1, '1' union all select 2, 'd' union all select 2, '3'
union all select 2, 'r'
select * from #t
;with cte1 as
(
select
UniqueId
, id
, data
, case when isnumeric(data) = 1 then cast(data as int) end Level
from #t
union all
select
UniqueId
, id
, CAST('-' as varchar(10))
, Level - 1
from cte1
where Level > 0 )
,cte2 as
(
select id, GroupID = Dense_Rank() Over(Order by id),data, DataOrder = ROW_NUMBER() over(order by UniqueID, Level)
from cte1
where Level is null or data = '-'
)
SELECT
ID
, (select data + ','
from cte2 t2
where t2.GroupID = t1.GroupID
for XML path('')
) as ConcatData
from cte2 t1
group by t1.ID ,t1.GroupID
But the output is
ID ConcatData
1 a,b,-,-,-,
2 d,r,-,-,-,
That is I am not able to position the dashes('-') in between the characters.
Please help
Try this:
;with cte1 as
(
select
UniqueId
, id
, data
,case when isnumeric(data) = 1
THEN replicate(',-',data)
ELSE ',' + data end as string
from #t
)
select
id
,LTRIM(STUFF(
(
SELECT
' ' + t2.String
FROM Cte1 t2
WHERE t2.id = t1.id
FOR XML PATH('')
), 2, 1, ''
)) As concatenated_string
from cte1 t1 group by t1.ID ,t1.ID
Works for the sample data bove and might be a bit quicker than using cursors
Following is the table creating
Create table #temp
(
IDUnique int Identity(1,1),
ID int,
data varchar(100)
)
Following are the records suggested by you.
Insert into #temp(ID, data) Values(1, 'a')
Insert into #temp(ID, data) Values(1, '2')
Insert into #temp(ID, data) Values(1, 'b')
Insert into #temp(ID, data) Values(1, '1')
Insert into #temp(ID, data) Values(2, 'd')
Insert into #temp(ID, data) Values(2, '3')
Insert into #temp(ID, data) Values(2, 'r')
Following is the cursor implementation
declare #IDUnique int
declare #ID int
declare #data varchar(100)
declare #Latest int
declare #Previous int
declare #Row int
set #Latest = 1
set #Previous = 1
Create Table #temp1
(
ID int,
data varchar(100)
)
--SELECT Row_Number() Over(Order by IDUnique) Row, IDUnique, ID, data From #temp
DECLARE #getAccountID CURSOR SET #getAccountID = CURSOR FOR SELECT Row_Number() Over(Order by IDUnique) Row, IDUnique, ID, data From #temp
OPEN #getAccountID
FETCH NEXT FROM #getAccountID INTO #Row, #IDUnique, #ID, #data
WHILE ##FETCH_STATUS = 0
BEGIN
IF(#Row = 1)
Begin
Set #Previous = #ID
Set #Latest = #ID
Insert into #temp1(ID, data)values(#Previous, #data)
End
Else If (#Previous <> #ID)
Begin
Set #Previous = #ID
Set #Latest = #ID
Insert into #temp1(ID, data)values(#Previous, #data)
End
Else
Begin
Declare #number int
if(ISNUMERIC(#data) = 1)
Begin
Set #number = Convert(int , #data)
While(#number <> 0)
Begin
Update #temp1 Set Data = Data + ',-' Where ID = #ID
Set #number = #number - 1
End
End
Else
begin
Update #temp1 Set Data = Data + ',' + #data Where ID = #ID
End
End
FETCH NEXT FROM #getAccountID INTO #Row, #IDUnique, #ID, #data
END
CLOSE #getAccountID
DEALLOCATE #getAccountID
Select * from #temp1
Select * from #temp
Drop Table #temp
here is the Final Result set