I need to insert 2 values into a table based on other tables' select results.
IF NOT EXISTS
(
SELECT M.DNUM, M.NAME, U.ID, A.ID, A.RIGHT
FROM [ACCESS] A JOIN [MASTER] M
ON M.DNUM = A.NUM
JOIN [USERS] U
ON U.NUM = D.ID
WHERE M.ALIAS = '0-50'
GROUP BY M.DNUM, M.NAME, U.ID, A.ID, A.RIGHT
)
BEGIN
INSERT INTO [ACCESS]
(ID, RIGHT)
VALUES
('9','3')
END
I need to add the 2 values to the [ACCESS] table but only want to add the values if M.ALIAS is 0-50 AND if A.NUM = M.NUM.
When I ran the script it completed without error but insert did not happen when I recheck.
Thank you for your help.
Add ELSE clause with PRINT to test IF condition
Related
I have a stored procedure that accepts a user defined table type, which is just a list of ints.
If the table is not set (Either sent in as NULL, or has no rows), then my existing query to return data is OK. But I need to only return Ids that are in that table variable.
So if the table variable has data, I would like to INNER JOIN on it, to only return matching Ids.
So that the moment, it's a basic query like this: (Example)
SELECT ...
FROM MyTable
Where UserId = 1
But I need to somehow:
SELECT ...
FROM MyTable m
INNER JOIN #MyTableVariable v ON v.Id = m.Id, --But only if #MyTableVariable has data
Where UserId = 1
Can I do the inner join, only when there's data in #MyTableVriable? Or maybe EXITSTS would help?
Of course, a relatively simple approach (assuming your SELECT statement is not too complicated and you don't mind "duplicating" it) would be:
IF EXISTS (SELECT 1 FROM #MyTableVariable)
BEGIN
SELECT ...
FROM MyTable m
INNER JOIN #MyTableVariable v ON v.Id = m.Id, --But only if #MyTableVariable has data
Where UserId = 1;
END
ELSE
BEGIN
SELECT ...
FROM MyTable m
Where UserId = 1;
END
Otherwise
SELECT ...
FROM MyTable m
LEFT OUTER JOIN #MyTableVariable v ON v.Id = m.Id, --But only if #MyTableVariable has data
Where UserId = 1
AND
(
(EXISTS (SELECT 1 FROM #MyTableVariable)
AND v.Id Is Not NULL)
OR
(NOT EXISTS (SELECT 1 FROM #MyTableVariable))
);
I'll stand corrected if I'm wrong (just don't have the opportunity to test it myself right now), but I believe that even if NULL was passed in as the #MyTableVariable value, SQL would still see it as an empty table (with the corresponding structure of the UDT)
SQL Server provides conditional statemets; then, you can try this approach bellow, with a conditional select, based on your table variable status (in this example, checking if is not empty):
IF(EXISTS(SELECT 1 FROM #MyTableVariable))
BEGIN
SELECT ...
FROM MyTable m
INNER JOIN #MyTableVariable v ON v.Id = m.Id
WHERE UserId = 1
END
ELSE
BEGIN
SELECT ...
FROM MyTable
WHERE UserId = 1
END
I need to update CTE o/p one of the column value (top 1 record) based on the latest timestamp & then return.
Query
WITH cte AS (
select
dt_zone.zone_name,
dt_material_status.mtstatus_name,
dt_historicalzone.visit_time_in
FROM ((public.dt_historicalzone
INNER JOIN dt_material_status
ON dt_historicalzone.mtstatus_id = dt_material_status.mtstatus_id)
INNER JOIN dt_zone ON dt_historicalzone.zone_id = dt_zone.zone_id)
WHERE material_id = 'ELS46885'
ORDER BY dt_historicalzone.zone_id DESC)
UPDATE cte SET cte.mtstatus_name = true WHERE SELECT * FROM cte LIMIT 1;
SELECT * FROM cte
You may try using an update join, with Postgres' syntax, including a CTE for the limit portion of the query:
WITH cte AS (
SELECT dh.mtstatus_id
FROM dt_historicalzone dh
INNER JOIN dt_zone dz
ON dh.zone_id = dz.zone_id
ORDER BY zone_id DESC
LIMIT 1
)
UPDATE dt_material_status d
SET mtstatus_name = true
FROM cte t
WHERE d.mtstatus_id = t.mtstatus_id AND
d.material_id = 'ELS46885';
when you update a CTE, the background table is getting updated. You can have only one statement below CTE. Post that CTE loses its scope. You can only go for UPDATE statement, post CTE. I have modified the CTE and updated the top 1 row.
The above statement is applicable for SQL Server. In Postgres, the CTE cannot be target of UPDATE statements. See the below error in Postgres.
Query Error: error: relation "cte" cannot be the target of a modifying
statement
WITH cte AS (
select top 1
dt_zone.zone_name,
dt_material_status.mtstatus_name,
dt_historicalzone.visit_time_in
FROM public.dt_historicalzone
INNER JOIN dt_material_status
ON dt_historicalzone.mtstatus_id = dt_material_status.mtstatus_id
INNER JOIN dt_zone ON dt_historicalzone.zone_id = dt_zone.zone_id
WHERE material_id = 'ELS46885'
ORDER BY dt_historicalzone.zone_id DESC)
UPDATE cte
SET mtstatus_name = true
I have tried with sample data for a CTE update. Below works fine in SQL Server.
create table #test(a int)
create table #test2(a int, b int)
insert into #test values (1)
insert into #test2 values (1,1)
;WITH CTE as
(
select top 1 t.a, t2.b
FROM #test as t
join #test2 as t2
on t.a = t2.a
order by t.a desc
)
update cte set b = 0
select * from #test2
This query is fine works.
SELECT * FROM TABLE WHERE 330110042 IN (iItem01,iItem02,iItem03,iItem04,iItem05,iItem_1,iItem_2,iItem_3,iItem_4,iItem_5,iItem_6,iItem_7,iItem_8,iItem_9,iItem_10,iItem_11,iItem_12,iItem_13,iItem_14,iItem_15,iItem_16,iItem_17,iItem_18,iItem_19,iItem_20,iItem_21,iItem_22,iItem_23,iItem_24,iItem_25,iItem_26,iItem_27,iItem_28,iItem_29,iItem_30)
But this query didnt work.
SELECT * FROM TABLE WHERE 330110042, 330110002, 330110002 IN (iItem01,iItem02,iItem03,iItem04,iItem05,iItem_1,iItem_2,iItem_3,iItem_4,iItem_5,iItem_6,iItem_7,iItem_8,iItem_9,iItem_10,iItem_11,iItem_12,iItem_13,iItem_14,iItem_15,iItem_16,iItem_17,iItem_18,iItem_19,iItem_20,iItem_21,iItem_22,iItem_23,iItem_24,iItem_25,iItem_26,iItem_27,iItem_28,iItem_29,iItem_30)
How i work in SQL Server?
It's difficult to tell your exact goal here, but one possibility would be to turn the list of values into a table structure of its own. A Common Table Expression might work:
;WITH Ids AS
(
SELECT 330110042 AS Id
UNION ALL
SELECT 330110002
)
SELECT t.*
FROM [Table] t
INNER JOIN Ids i ON t.iItem01 = i.Id OR t.iItem02 = i.Id OR...
But, maybe a solution with UNPIVOT would be more elegant. I presume that your table has a primary key column called Id:
;WITH Unpivoted AS
(
SELECT Id, ColName, ColValue
FROM (SELECT Id, iItem01, iItem02, iItem03
FROM [Table] t) p
UNPIVOT
(ColValue FOR ColName IN (iItem01, iItem02, iItem03)) AS unpvt
)
SELECT t.*
FROM [Table] t
WHERE EXISTS (SELECT 1 FROM Unpivoted u
WHERE t.Id = u.Id
AND u.ColValue IN (330110042, 330110002))
Of course, you would add all the necessary columns. I added only the first three for this example.
I'm new to T-SQL and trying to do some cleanup on some data imported from Excel into SQL Server.
I have made a batch import that imports the raw data to a staging table and now I want to clean it up.
I have the following tables
tblRawInput (my stageing table):
Name, Name2, Name3, Phonenumber, Group
tblPeople:
PersonID (IDENTITY), Name, Phonenumber, GroupID
tblGroups:
GroupID (IDENTITY), Groupname
tblAltNames:
NameID (IDENTITY), Name, PersonID
The query should be able to split the data into the other tables, but not create a group if it already exists.
I am at a loss. Could anyone give me a pointer in the right direction.
When I do a SELECT INTO it creates multiple copies of the groups.
You can use a not exists clause to insert only new groups:
insert into Groups
(GroupName)
select distinct Group
from tblRawInput ri
where not exists
(
select *
from Groups
where g.GroupName = ri.Group
)
After this, you can insert into tblPeople like;
insert tblPeople
(Name, GroupID)
select ri.Name
, g.GroupID
from tblRawInput ri
-- Look up GroupID in the Groups table
join Groups g
on g.GroupName = ri.Group
You can do the alternate names along the same lines.
First in this case order matters. Insert to groups first.
insert into tblGroups
(GroupName)
select Group
from tblRawInput ri
where not exists
(
select *
from tblGroups g
where g.GroupName = ri.Group
)
Then insert to the people table
Insert into tblPeople(Name, Phonenumber, GroupID)
Select Name, Phonenumber, GroupID
from tblRawInput ri
join tblGroups g
on g.groupName = ri.group
where not exists
(
select *
from tblPeople p
where p.Name = ri.Name
and p.Phonenumber = ri.Phonenumber
and p.groupId = g.groupid
)
Then get the alt name
Insert into tblAltNames (Name, Personid)
Select Distinct Name2, PersonID
from tblRawInput ri
join tblPerson p
on p.Name = ri.Name
where not exists
(
select *
from tblAltNames p
where p.Name = ri.Name2
)
Of course all of this should be wrapped in a transaction and a try catch block with a rollback of everything is one of the inserts fails.
Possibly the second query shoudl use the output clause to get teh personids inserted instead of the join. You don't really have anything good to join on here because names are not unique.
I want to retrieve the parentid of an id, if that parentid has a parent again retrieve it, and so on.
Kind of hierarchy table.
id----parentid
1-----1
5-----1
47894--5
47897--47894
am new to sql server and tried, some queries like:
with name_tree as
(
select id, parentid
from Users
where id = 47897 -- this is the starting point you want in your recursion
union all
select c.id, c.parentid
from users c
join name_tree p on p.id = c.parentid -- this is the recursion
)
select *
from name_tree;
It is giving me only one row.
and also I want to insert these records into a temporary table variable.
How can I do this. thanks in advance. sorry for asking the simple question(though not to me)
Try this to get all parents of a child
;with name_tree as
(
select id, parentid
from Users
where id = 47897 -- this is the starting point you want in your recursion
union all
select C.id, C.parentid
from Users c
join name_tree p on C.id = P.parentid -- this is the recursion
-- Since your parent id is not NULL the recursion will happen continously.
-- For that we apply the condition C.id<>C.parentid
AND C.id<>C.parentid
)
-- Here you can insert directly to a temp table without CREATE TABLE synthax
select *
INTO #TEMP
from name_tree
OPTION (MAXRECURSION 0)
SELECT * FROM #TEMP
Click here to view result
EDIT :
If you want to insert into a table variable, you can do something like:
-- Declare table varialbe
Declare #TABLEVAR table (id int ,parentid int)
;with name_tree as
(
select id, parentid
from #Users
where id = 47897 -- this is the starting point you want in your recursion
union all
select C.id, C.parentid
from #Users c
join name_tree p on C.id = P.parentid -- this is the recursion
-- Since your parent id is not NULL the recursion will happen continously.
-- For that we apply the condition C.id<>C.parentid
AND C.id<>C.parentid
)
-- Here you can insert directly to table variable
INSERT INTO #TABLEVAR
select *
from name_tree
OPTION (MAXRECURSION 0)
SELECT * FROM #TABLEVAR
Click here to view result
Your query is doing recursion but in opposite direction. So if you change starting point to:
where id = 1
then you will have user 1 and all his successors
you didn't mention the desired output and input.
However you can try like this,
Declare #t table (id int ,parentid int)
insert into #t
select 1,1 union all
select 5,1 union all
select 47894,5 union all
select 47897,47894
;With CTE as
(
select * from #t where id=1
union all
Select a.* from #t a inner join cte b
on b.id=a.parentid and
a.id<>b.id
)
select * from cte