TSQL - The multi-part identifier bounding error - sql

CREATE FUNCTION [dbo].[Test] (#ID INT, #VAL INT)
RETURNS #Return TABLE (ID INT, VAL INT)
AS
BEGIN
INSERT INTO #Return
SELECT #ID, #VAL
RETURN;
END
GO
DECLARE #T1 TABLE (ID INT IDENTITY(1,1), VAL INT)
DECLARE #T2 TABLE (ID INT, VAL INT)
INSERT INTO #T1
SELECT 1
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
INSERT INTO #T2
SELECT 1,1
UNION
SELECT 2,4
UNION
SELECT 3,3
SELECT *
FROM #T1 T1
LEFT JOIN #T2 T2 ON T1.[ID] = T2.[ID]
LEFT JOIN [dbo].[Test] (1, COALESCE(T2.[VAL],T1.VAL)) T ON T1.ID = T.ID
GO
DROP FUNCTION [dbo].[Test]
GO
Goal:
To pass in T2.Val into the 2nd param of the fx if available, else pass in T1.Val. Changing the FX definition is not possible.
I can't seem to get this work. I tried ISNULL and that doesn't work either.

If you want to call a table valued function, use APPLY (OUTER APPLY in this case because you are using LEFT JOIN):
SELECT *
FROM #T1 T1 LEFT JOIN
#T2 T2
ON T1.[ID] = T2.[ID] OUTER APPLY
[dbo].[Test](1, COALESCE(T2.[VAL], T1.VAL) ) T;
If you want an additional condition, then use a WHERE clause:
SELECT *
FROM #T1 T1 LEFT JOIN
#T2 T2
ON T1.[ID] = T2.[ID] OUTER APPLY
[dbo].[Test](1, COALESCE(T2.[VAL], T1.VAL) ) T
WHERE t1.ID = T.ID;
That last condition seems strange, though. Why not just pass T1.ID into the function directly?

Related

Update statement with Where Not Exists

I am trying to do the following:
Set the status column to 1 when the row in the first table (variable) does not exist in the second one.
I tried this:
update #table1
set status=1
where NOT EXISTS (select top 1 1 from #table2 where #table1.foo=#table2.foo)
But this doesn't even compile, not recognizing #table1 in the Where statement.
Must declare the scalar variable "#table1".
Any clue about this?
Your approach is fine. You just need table aliases because the # is used to in SQL Server to represent variables (scalars or tables) and is hence problematic for aliases:
update t1
set status = 1
from #table1 t1
where not exists (select 1 from #table2 t2 where t2.foo = t1.foo);
Note that the top 1 is unnecessary in the subquery.
You can do this kind of thing by joining the two tables with a LEFT JOIN and checking the right side for NULL:
UPDATE t1
SET t1.status=1
FROM #table1 t1
LEFT JOIN #table2 t2
ON t1.foo = t2.foo
WHERE t2.foo IS NULL
The specific error you got is because you haven't got a statement declaring #table1 as a table variable, like DECLARE #table1 TABLE (foo int) for example. If table1 is not a variable, you don't need the #.
no need any top inside scaler query
update #table1
set status=1
where NOT EXISTS (select 1 from #table2 where #table1.foo=#table2.foo)
cause exists return boolean
you could use below query
update #table1
set status=1
where #table1.foo not in ( select foo from #table2 where foo is not null)
There are multiple ways - inner query with NOT IN and NOT EXISTS and JOIN query:
update tab1 set status = 1 where name not in (select name from tab2);
update tab1 set status = 1 where not exists (select 1 from tab2 where tab1.name=tab2.name);
update tab1 set status = 1 from tab1 left outer join tab2 on tab1.name = tab2.name where tab2.name is null;
Sample schema to run above queries;
create table tab1(name varchar(30), status int);
create table tab2(name varchar(30));
insert into tab1 values('a', 5);
insert into tab1 values('b', 6);
insert into tab1 values('c', 7);
insert into tab1 values('d', 8);
insert into tab2 values('a');
insert into tab2 values('d');
You have to declare table1 and table2 variables
DECLARE #table1 YOUR_TABLE1_NAME;
DECLARE #table2 YOUR_TABLE2_NAME;
update #table1
set status=1
where NOT EXISTS (select top 1 from #table2 where #table1.foo=#table2.foo)
You should use alias name for both table.
DECLARE #TABLE_1 TABLE (DEPT_NAME VARCHAR(50),DEP_ID INT)
INSERT INTO #TABLE_1(DEPT_NAME,DEP_ID)
SELECT 'IT',1 UNION ALL
SELECT 'HR',2 UNION ALL
SELECT 'ACCOUNT',3 UNION ALL
SELECT 'ADMIN',4 UNION ALL
SELECT 'SALES',5 UNION ALL
SELECT 'CEO',7
DECLARE #TABLE_2 TABLE (E_ID INT,EMP_NAME VARCHAR(50),DEP_ID INT)
INSERT INTO #TABLE_2(E_ID,EMP_NAME,DEP_ID)
SELECT 1,'JHON',1 UNION ALL
SELECT 2,'LITA',2 UNION ALL
SELECT 3,'MATT',1 UNION ALL
SELECT 4,'JEFF',1 UNION ALL
SELECT 5,'BROCK',2 UNION ALL
SELECT 6,'BOB',5 UNION ALL
SELECT 7,'SAM',4 UNION ALL
SELECT 8,'DAVID',3 UNION ALL
SELECT 9,'JACK',1 UNION ALL
SELECT 10,'GARY',4 UNION ALL
SELECT 11,'DONALD',6
SELECT * FROM #TABLE_1 A WHERE NOT EXISTS (SELECT DEP_ID FROM #TABLE_2 B WHERE A.DEP_ID=B.DEP_ID )

SQL Server hierarchy referencing and cross data referencing

This might be a stupid question, but I am not a DBA and kind of stuck with this issue. I have an application that trickles down all effects (asdf) under an applied ID (IDParent).
The data tables are setup like this:
Data Tables
3rd Data Table
I want to write a query that when using IDChild it will reference that entry's IDParent to get the parent ID while referencing it as an IDChild. For example for the data entry starting at 116 I want to use the parent ID (124) and get 321 in T1. I want to use this to get the RandoName associated with RandoID for all of the entries that has a parent ID of 321.
Right now I am using a script something like:
Select t.[NAME]
From T2 tv
Inner join T3 t on t.RandoID = tv.RandoId
Where
tv.IDChild = T1.IDChild OR tv.IDChild = T1.IDParent
but I'm not sure how to get the whole applied hierarchy.
This would yield something like this:
Resulting Query
PS. I can not change the tables/db schema. But maybe I can add one to do all the referencing? Please tell me what you think.
EDIT I'm sorry I forgot about this other stupid table that RandoID uses which contains the name of the RandoID. I am trying to get the name of RandoID
I think a loop could help you.
Try this:
CREATE TABLE #t1 (IDChild Int, IDParent Int);
CREATE TABLE #t2 (RandoID NVARCHAR(10) , IDChild Int);
CREATE TABLE #RandoName (RandoID NVARCHAR(10), RandoName VARCHAR(50));
INSERT INTO #t1 VALUES (321, NULL), (123,321),(124,123),(116,124)
INSERT INTO #t2 VALUES ('asdf', 123)
INSERT INTO #RandoName VALUES ('asdf', 'something')
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 100)) [RowNum], a.IDChild a, a.IDParent b, b.IDChild c INTO #t3 FROM #t1 a
LEFT OUTER JOIN #t1 b ON b.IDParent = a.IDChild
DECLARE #rownum INT;
DECLARE cbcursor CURSOR for Select RowNum FROM #t3;
OPEN cbcursor;
Fetch Next from cbcursor into #rownum
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE #t3
SET c = (SELECT b from #t3 where RowNum = #rownum-1)
WHERE RowNum = #rownum
Fetch Next from cbcursor into #rownum;
END;
Close cbcursor;
Deallocate cbcursor;
SELECT a,b,t2.RandoID, r.RandoName FROM #t3
LEFT OUTER JOIN #t2 t2 on t2.IDChild = #t3.c OR t2.IDChild = #t3.b OR t2.IDChild = #t3.a
LEFT OUTER JOIN #RandoName r on t2.RandoID = r.RandoID
This is what I get:
If you have any changes in your tables, like more records for T2, this script should be modified.
Using recursion:
declare #t table (IDc int , Idp int)
insert into #t
values
(321,null)
,(123,321)
,(124,123)
,(116,124)
declare #t2 table (RandoID varchar(10), IDChild int)
insert into #t2
values('asdf',123)
;with cte as
(
select anchor = IDChild
,ParentOrSelf = IDc
,RandoID
,RandomName
from #t
cross join (select RandoID,RandoName from #t2 t2 join #t3 t3 on t2.RandoID=t3.RandoID) crossed
where IDc=#anchor
union all
select t2.IDChild
,IDc
, t2.RandoID,RandomName
from #t t
cross join (select RandoID,RandoName from #t2 t2 join #t3 t3 on t2.RandoID=t3.RandoID) t2
join cte on cte.ParentOrSelf = t.Idp
)
select IDc
, cte.RandoID,cte.RandomName
from #t t
left join cte on t.IDc = cte.ParentOrSelf
Results:
IDc RandoID
321 NULL
123 asdf
124 asdf
116 asdf

SQL Server: Delete from table based on value of another table

I want to delete from t2 if same value of itemid,storeid,MSRTime does not exist on t1 and Same value of itemid,storeid,MSRTime exist on t3 and status is D. In below example i should be able to delete second row on t2 but not 1st row.
Table 1: t1
itemid |storeid|MSRTime
x y z
Table 2: t2
itemid |storeid|MSRTime
x y z
a b c
Table 3: t3
itemid |storeid|MSRTime|status
x y z D
a b c D
I tried doing this using join but i could not reach the desired result. Please help.
Thank You.
You can write the query almost exactly as you've described it:
declare #t1 table(itemid varchar(7),storeid varchar(9),MSRTime varchar(3))
insert into #t1(itemid,storeid,MSRTime) values
('x','y','z')
declare #t2 table(itemid varchar(7),storeid varchar(9),MSRTime varchar(3))
insert into #t2(itemid,storeid,MSRTime) values
('x','y','z'),
('a','b','c')
declare #t3 table(itemid varchar(7),storeid varchar(9),MSRTime varchar(3),status varchar(4))
insert into #t3(itemid,storeid,MSRTime,status) values
('x','y','z','D'),
('a','b','c','D')
delete from t2
from #t2 t2
inner join
#t3 t3
on
t2.itemid = t3.itemid and
t2.storeid = t3.storeid and
t2.MSRTime = t3.MSRTime and
t3.status = 'D'
where
not exists (
select *
from #t1 t1
where t1.itemid = t2.itemid and
t1.storeid = t2.storeid and
t1.MSRTime = t2.MSRTime
)
select * from #t2
Result:
itemid storeid MSRTime
------- --------- -------
x y z
Should be something like this
-- delete t2
select *
from table2 t2
JOIN table3 t3 on t2.itemid = t3.itemid and
t2.storeid = t3.storeid and
t2.MSRTime = t3.MSRTime
LEFT JOIN table1 t1 on t2.itemid = t1.itemid and
t2.storeid = t1.storeid and
t2.MSRTime = t1.MSRTime
where t1.itemID IS NULL
Run the select first, if it gives you back right row, just un-comment delete and you are good to go
I have created the whole script for your reference. Please use the last DELETE query for your scenario. That will do the trick.
CREATE TABLE #T1
(itemid VARCHAR(10)
,storeid VARCHAR(10)
,MSRTime VARCHAR(10))
INSERT INTO #T1 VALUES ('x','y','z')
SELECT * FROM #T1
GO
CREATE TABLE #T2
(itemid VARCHAR(10)
,storeid VARCHAR(10)
,MSRTime VARCHAR(10))
INSERT INTO #T2 VALUES ('x','y','z'),('a','b','c')
SELECT * FROM #T2
GO
CREATE TABLE #T3
(itemid VARCHAR(10)
,storeid VARCHAR(10)
,MSRTime VARCHAR(10)
,status VARCHAR(10))
INSERT INTO #T3 VALUES ('x','y','z','D'),('a','b','c','D')
SELECT * FROM #T3
GO
DELETE M
FROM #T2 AS M INNER JOIN
(SELECT itemid,storeid,MSRTime FROM
(SELECT itemid,storeid,MSRTime FROM #T3 WHERE status='D') T1
INTERSECT
(SELECT itemid,storeid,MSRTime FROM
(SELECT * FROM #T2
EXCEPT
SELECT * FROM #T1) T2)) X
ON X.itemid = M.itemid AND X.storeid = M.storeid AND X.MSRTime = M.MSRTime
GO
Not sure if this matches your environment, but programmatically it may be beneficial to limit the results you are comparing with the joins to only those that have a value of D in status. I would also try making a compound key using Coalese so that you are not having to match on three separate joins.
For example -
itemid |storeid|MSRTime|Key
x y z xyz
a b c abc

interesting t-sql exercise

I am trying to resolve t-sql exercise
I need to update first table with values from second by joining by id. If I can not join then use value from default ID (default iD is the Id that is null)
please run it to see it
declare #t as table (
[id] INT
,val int
)
insert into #t values (null, null)
insert into #t values (2, null)
insert into #t values (3, null)
insert into #t values (4, null)
declare #t2 as table (
[id] INT
,val int
)
insert into #t2 values (null, 11)
insert into #t2 values (2, 22)
insert into #t2 values (3, 33)
select * from #t
select * from #t2
update t
set t.val = t2.val
from #t as t join #t2 as t2
on t.id = t2.id
or
(
(t.id is null or t.id not in (select id from #t2))
and t2.id is null
)
select * from #t
here is result
--#t
id val
---------------
NULL NULL
2 NULL
3 NULL
4 NULL
--#t2
id val
---------------
NULL 11
2 22
3 33
--#t after update
id val
---------------
NULL 11
2 22
3 33
4 NULL
how to make val in last row equal 11?
4 11
This solution left joins to t2 twice and then does a coalesce.
The ON on the second join matches on records that failed on the join and then looks for the "Default" case.
UPDATE t
set t.val = COALESCE(t2.val,t3.val)
from #t as t
LEFT join #t2 as t2
on t.id = t2.id
LEFT JOIN #t2 t3
ON t2.id is null and t3.id is null
See it working here
try this for the update...
update t
set t.val = t2.val
from #t as t join #t2 as t2
on t.id = t2.id
or
(
(t.id is null or not exists (select * from #t2 where id = t.id))
and t2.id is null
)
Problem is with not in operator and null values. This would also work...
update t
set t.val = t2.val
from #t as t join #t2 as t2
on t.id = t2.id
or
(
(t.id is null or t.id not in (select id from #t2 where id is not null))
and t2.id is null
)
Here's a technique that may help.
Start with the kind of simple code you want to be writing:
MERGE INTO #t AS target
USING source
ON target.id = source.id
WHEN MATCHED THEN
UPDATE
SET val = source.val;
Then write a table expression (source) that satisfies the requirements.
Requirement 1: "joining by id"
-- simple existential quantification e.g.
SELECT id, val
FROM #t2 AS T2
WHERE id IN ( SELECT id FROM #t )
Requirement 2: "If I can not join then use value from default ID (default iD is the Id that is null)"
-- first find the id values in the target that do not exist in the source:
SELECT id
FROM #t
EXCEPT
SELECT id
FROM #t2
then cross join the result with the row from the source where Id is null:
SELECT DT1.id, T2.val
FROM ( SELECT id
FROM #t
EXCEPT
SELECT id
FROM #t2 ) AS DT1,
#t2 AS T2
WHERE T2.id IS NULL
At this point you will want to query some test data to ensure each query satisfies its respective requirement.
Union the above two results to form a single table expression:
SELECT id, val
FROM #t2 AS T2
WHERE id IN ( SELECT id
FROM #t )
UNION
SELECT DT1.id, T2.val
FROM ( SELECT id
FROM #t
EXCEPT
SELECT id
FROM #t2 ) AS DT1,
#t2 AS T2
WHERE T2.id IS NULL
Then plug the table expression into the MERGE boilerplate code:
WITH source
AS
(
SELECT id, val
FROM #t2 AS T2
WHERE id IN ( SELECT id
FROM #t )
UNION
SELECT DT1.id, T2.val
FROM ( SELECT id
FROM #t
EXCEPT
SELECT id
FROM #t2 ) AS DT1,
#t2 AS T2
WHERE T2.id IS NULL
)
MERGE INTO #t AS target
USING source
ON target.id = source.id
WHEN MATCHED THEN
UPDATE
SET val = source.val;

How to return table from T-SQL Stored Procedure

SQL Newbie here, and I'm having a hell of a time finding what should be a simple code example to answer what I think is a simple question.
I need to write a stored procedure that does three things in order:
1) Select rows from one table
2) Update rows in another table, using values from the results table in #1
3) Return the results table from #1.
What I can't find is any example about how to return a value like this from a stored procedure. Also, how to retrieve that returned table from the caller (which is another T-SQL script).
Have a look at this.
DECLARE #Table1 TABLE(
ID INT,
VAL int
)
INSERT INTO #Table1 (ID,VAL) SELECT 1, 1
INSERT INTO #Table1 (ID,VAL) SELECT 2, 2
INSERT INTO #Table1 (ID,VAL) SELECT 3, 3
DECLARE #Table2 TABLE(
ID INT,
VAL VARCHAR(MAX)
)
INSERT INTO #Table2 (ID,VAL) SELECT 1, 1
INSERT INTO #Table2 (ID,VAL) SELECT 2, 2
INSERT INTO #Table2 (ID,VAL) SELECT 3, 3
--Lets say this is the 2 tables
--now this will go into the sp
UPDATE #Table1
SET Val = t1.Val + t2.Val
FROM #Table1 t1 INNER JOIN
#Table2 t2 ON t1.ID = t2.ID
SELECT t1.*
FROM #Table1 t1 INNER JOIN
#Table2 t2 ON t1.ID = t2.ID
--and you can insert into a var table in the tsql script that calls the sp
DECLARE #Table1TSQL TABLE(
ID INT,
VAL int
)
INSERT INTO #Table1TSQL (ID,VAL) EXEC YourSP