Why No Error in T-SQL? - sql

When the following SQL is run you don't get an error in either SQL version 2005 or 2008 R2.
select 1 as MyVal, 'string' as MyText
into #table1
select 1 as thisColumnDoesntExistInTable1, 'string' as MyText
into #table2
select * from #table1
select * from #table2
-- WHY NO ERROR HERE ---
select *
from #table2
where thisColumnDoesntExistInTable1 in
(
select thisColumnDoesntExistInTable1 from #table1
)
drop table #table1
drop table #table2
But if you change the statement as follows by adding an alias to the inner select...
select *
from #table2
where thisColumnDoesntExistInTable1 in
(
select a.thisColumnDoesntExistInTable1 from #table1 a
)
...you do get an error.

Effectively, you have this. So no error
select * from #table2 t2
where thisColumnDoesntExistInTable1 in
(select t2.thisColumnDoesntExistInTable1 from #table1 )
When you qualify this to be explicit for table1, you get the error

The scope of the query is available in the subselect. You can see this more clearly if you change what's in #table2.
select 1 as MyVal, 'string' as MyText
into #table1
select 2 as thisColumnDoesntExistInTable1, 'string' as MyText
into #table2
select * from #table1
select * from #table2
select * from #table2 where thisColumnDoesntExistInTable1 in (select thisColumnDoesntExistInTable1 from #table1 )
drop table #table1
drop table #table2
So you can see, the result will show 2 instead of 1 because you're accessing the value of thisColumnDoesntExistInTable1 from #table2.

Column thisColumnDoesntExistInTable1 does not, as it says, exist in #table1. In the first query, when the compiler hits the subquery, since the column is not aliased it looks in all tables involved in the query, finds it in one, and uses it from there. In the second query, the column is aliased, so SQL only checks the referenced table for the column, doesn't find it, and throws the error.

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 )

Create table in SQL Server using union

In mysql we write query as
create table new_table as (select a.* from Table1 a union select b.* from Table2 b)
This syntax doesn't work in SQL Server - what's the way around for creating a table from union in SQL Server?
in SQL Server, you can use SELECT .. INTO
select a.*
into new_table
from Table1 a
union
select b.*
from Table2 b
The following query should do what you want:
select * into new_table
from (
select * from Table1 union select * from Table2 ) a
You need to write your query as shown below for creating table in sql server using union clause.
create table #table1 (Id int, EmpName varchar(50))
insert into #table1 values (1, 'Suraj Kumar')
create table #table2 (Id int, EmpName varchar(50))
insert into #table2 values (2, 'Davinder Kumar')
SELECT * INTO #NewTable FROM
(SELECT Id, EmpName FROM #table1
UNION
SELECT Id, EmpName FROM #table2
)a
SELECT * FROM #NewTable
Here new table of name - #NewTable has been created by union of two tables #table1 and #table2

update each row (sql server) based on subquery

I want to update each row of table1->keyField based on table2 value
Table1
Id|keyField
1|test_500
2|test_501
3|test_501
500,501 are primary key of and my another table2
Table2
Id|value
500|A
501|B
502|C
I have tried something like
update table1 set keyField=(select value from table2 where id=substring(expression))
but my select return multiple statement so unable to run the query.
any help or direction please?
You can use the syntax like this
UPDATE table1 SET keyField = Table2.Value
FROM table1 INNER JOIN table2
ON table1.Id = substring(expression))
If I get it right, this might be what you need:
UPDATE T1 SET
keyField = T2.Value
FROM
Table1 AS T1
INNER JOIN Table2 AS T2 ON T2.id = SUBSTRING(T1.keyField, 6, 100)
Careful when comparing substring result with an numeric value, might get a conversion error.
Try this code (necessary notes are in comments below):
--generate some sample data (the same as you provided)
declare #table1 table (id int, keyField varchar(10))
insert into #table1 values (1,'test_500'),(2,'test_501'),(3,'test_502')
declare #table2 table (id int, value char(1))
insert into #table2 values (500,'A'),(501,'B'),(502,'C')
--in case you want to see tables first
--select * from #table1
--select * from #table2
--here you extract the number in first table in keyField column and match it with ID from second table, upon that, you update first table
update #table1 set keyField = value from #table2 [t2]
where cast(right(keyfield, len(keyfield) - charindex('_',keyfield)) as int) = [t2].id
select * from #table1

Multi-part identifer issue when joining table to function

THE QUESTION:
My join is not working as expected:
join db1.function1(t1.id) f1 on f1.id = t1.id
The error message is:
Incorrect syntax near '.'.
The multi-part identifier 't1.id' could not be found.
This bit (t1.id) is underlined with a red squiggly line.
I get the same issue when I try to use cross apply.
The function is a table-valued function, so returns a table.
FULL QUERY EXAMPLE:
select t1.*, f1.*
FROM db1.dbo.table1 t1
join db1.dbo.function1(t1.id) f1 on f1.id = t1.id
SIMPLIFIED VERSION OF THE FULL FUNCTION:
USE [DB1]
ALTER FUNCTION [dbo].[function1](#id int)
RETURNS #return_table TABLE (
id INT,
col1 INT,
col2 VARCHAR(255)
)
AS
BEGIN
-- ...
-- do all sorts of stuff here to get needed data, temp tables, unions, joins, inserts, selects etc
-- ...
INSERT INTO #return_table (id, col1, col2)
select distinct id, col1,
(
select isnull(cast(col2 as varchar(3)),'NULL')+','
from #tbl2 t2
where t2.id = t1.id
for xml path('')
) col2
from #tbl1 a1
RETURN;
END;
Hi So basically you are looking to perform a INNER JOIN. The problem you are fasing is that you are using a Function. What you should be using to achieve is a CROSS JOIN. If left Join is desired, you could use a OUTER JOIN
There is a great artical that explains in detail that has helped me in the past and can be navigated to by following this link. ClickMe. Search for Use case 5: APPLY and TVFs
I have also written a code that may be of some assistance for the immediate request
Test Data:
IF OBJECT_ID(N'Test1')>0
BEGIN
DROP TABLE Test1
END
CREATE TABLE Test1 (Tbl1ID INT IDENTITY(1, 1),
Name VARCHAR(250))
INSERT INTO Test1
VALUES('ABCD1'),
('ABCD2'),
('ABCD3'),
('ABCD4'),
('ABCD5'),
('ABCD6')
IF OBJECT_ID(N'Test2')>0
BEGIN
DROP TABLE Test2
END
CREATE TABLE Test2 (Tbl2ID INT IDENTITY(1, 1),
Name VARCHAR(250))
INSERT INTO Test2
VALUES('ABCD1'),
('ABCD2'),
('ABCD4'),
('ABCD5')
GO
TV Function:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ufn_TVFTable2]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[ufn_TVFTable2]
GO
CREATE FUNCTION ufn_TVFTable2 (#Name NVARCHAR(1000))
RETURNS TABLE
AS
RETURN
SELECT *
FROM Test2
WHERE Name = #Name
GO
Usage:
SELECT t.*,tf.*
FROM Test1 AS T
CROSS APPLY dbo.ufn_TVFTable2(T.name) AS tf
Cleanup:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ufn_TVFTable2]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[ufn_TVFTable2]
GO
IF OBJECT_ID(N'Test1')>0
BEGIN
DROP TABLE Test1
END
IF OBJECT_ID(N'Test2')>0
BEGIN
DROP TABLE Test2
END
Your Query would look like below:
SELECT t1.*,
f1.*
FROM db1.dbo.table1 AS t1
CROSS APPLY db1.dbo.function1(t1.id) AS f1
Usage Example 2:
;WITH cte_table1(ID) AS
(
SELECT 82938382 AS ID UNION ALL
SELECT 82938383 AS ID UNION ALL
SELECT 82938384 AS ID UNION ALL
SELECT 82938385 AS ID
)
SELECT t1.*,
f1.*
FROM db1.dbo.table1 AS t1
CROSS APPLY db1.dbo.function1(t1.id) AS f1
You are trying to join onto a function using a column from table1 before the join has actually happened. Think of the return of function1 as an atomic operation which you are then joining to table1. So at that point, SQL doesn't know what the value of the id column is.
Assuming function1 does not return a table, you probably wanted to do this:
SELECT t1.*, db1.dbo.function1(t1.id)
FROM db1.dbo.table1 t1

CTE in From clause of SQL Query

I need to use CTE query inside from clause of SQL Query
See this example:
Drop Table #Temp
Drop Table #Temp2
Create Table #Temp(name1 text, name2 text)
Insert INTO #Temp Values ('test','test')
Insert INTO #Temp Values ('test','test')
select * into #Temp2
from #Temp
Select * from #Temp2
Here, I am just inserting rows into temp table 'Temp2' from selecting records from Temp... this is working fine...
But my need is, have to use CTE inside from clause.. like
select * into #Temp2
from (;With CTE as ( Select * from #Temp) select * from CTE)
Please don't encourage me to separate CTE query..because, I can't control that part of query since it is being provided by other system.
select * into #Temp2
from ("Query Provided by Other System")
So the "Query Provided by Other System" may or may not be the CTE query.
Check with below syntax, its worked for me and i hope you are looking for same:
With CTE as ( Select * from #Temp)
select * into #Temp2 from CTE
use below query
Create Table #Temp(name1 text, name2 text)
Insert INTO #Temp Values ('test','test')
Insert INTO #Temp Values ('test','test')
GO
With CTE as ( Select * from #Temp)
select * into #Temp2 from CTE
select * from #Temp2
GO
Drop Table #Temp
Drop Table #Temp2