I trying to change this to be dynamic but I stuck at the set of data..
Example, the statement
SELECT * FROM A
WHERE id IN (1,2)
and also 1,2 come from
SELECT id FROM B
WHERE type='%xxx%'
Statement above can return many number
I try to declare #id but I have no idea
So, Have any idea?
Thank you for suggestion :)
SELECT * FROM A
WHERE id IN (
SELECT id FROM B
WHERE type='%xxx%')
This is called a subquery.
EDIT: When using a subquery is not an option and you want to use a variable, you can declare a temporary table and join table A with that table.
DECLARE #C table (id int)
INSERT #C (id)
SELECT id FROM B
WHERE type='%xxx%'
SELECT A.*
FROM A INNER JOIN #C c ON A.id = c.id
SELECT A.* FROM A
INNER JOIN B
WHERE B.type='%xxx%'
AND A.ID = B.ID
Perhaps you can just use inner join, it should return you the result set that you looking at
Related
I have two table in my same DB
create table a(gr_code nvarchar, code int)
insert into a values('1',100),('0',200),('1',200),('0',100)
create table b(gr_code nvarchar, code int)
insert into b values('1',100),('0',200)
find the code in table A which does not have in table B for particular gr_code
expected result:
gr_code code
1 200
0 100
It's quite simple using the clause exists
select *
from a
where not exists (select *
from b
where b.gr_code = a.gr_code and
b.code = a.code)
This returns the result on your sample.
Use LEFT JOIN
select a.*
from a
left join b on a.gr_code = b.gr_code and a.code = b.code
where b.gr_code is null
You can use LEFT JOIN like this:
SELECT a.*
FROM a
LEFT JOIN b on a.gr_code = b.gr_code
WHERE b.gr_code IS NULL
You can use EXCEPT like so:
select *
from a
except
select *
from b
If I have a sql statement like this:
select *
from tableA a
inner join tableB b on dbo.fn_something(a.ColX) = b.ColY
if you assume there are 5 rows in tableA with the same value for ColX will dbo.fn_something() be called with that value 5 times or just one time?
Clearly this is a trivial example, but I'm interested for the purposes of thinking about performance in a more complex scenario.
UPDATE
Thanks #DStanley, following from your answer I investigated further. Using SQL Profiler with the SP:StmtStarting event on the SQL below illustrates what happens. i.e. as you said: the function will be called once for each row in the join.
This has an extra join from the original question.
create table tableA
( id int )
create table tableB
( id_a int not null
, id_c int not null
)
create table tableC
( id int )
go
create function dbo.fn_something( #id int )
returns int
as
begin
return #id
end
go
-- add test data
-- 5 rows:
insert into tableA (id) values (1), (2), (3), (4), (5)
-- 5 rows:
insert into tableC (id) values (101), (102), (103), (104), (105)
-- 25 rows:
insert into tableB (id_a, id_c) select a.id, c.id from tableA a, tableC c
go
-- here dbo.fn_something() is called 25 times:
select *
from tableA a
inner join tableB b on a.id = b.id_a
inner join tableC c on c.id = dbo.fn_something(b.id_c)
-- here dbo.fn_something() is called just 5 times,
-- as the 'b.id_c < 102' happens to be applied first.
-- That's likely to depend on whether SQL thinks it's
-- faster to evaluate the '<' or the function.
select *
from tableA a
inner join tableB b on a.id = b.id_a
inner join tableC c on c.id = dbo.fn_something(b.id_c) and b.id_c < 102
go
drop table tableA ;
drop table tableB;
drop table tableC;
drop function dbo.fn_something;
go
It will be called for each row in a. I do not know of any optimization that would call the function just for unique inputs. If performance is an issue you could create a temp table with distinct input values and use thoce results in your join, but I would only do that it it was an issue - don't assume it's a problem and clutter your query unnecessarily.
If you declare your function as schema bound, it can be run one for each unique case. This requires that the function be deterministic and always has the same output for a given input.
CREATE FUNCTION dbo.fn_something (#id INT)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
RETURN #id
END
GO
I have 2 tables say A and B, and I want to do a join on them.
Table A will always have records in it.
When table B has rows in it, I want the query to turn all the rows in which table A and table B matches. (i.e. behave like inner join)
However, if table B is empty, I'd like to return everything from table A.
Is this possible to do in 1 query?
Thanks.
Yes, for results like this, use LEFT JOIN.
Basically what INNER JOIN does is it only returns row where it has atleast one match on the other table. The LEFT JOIN, on the other hand, returns all records on the left hand side table whether it has not match on the other table.
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
I came across the same question and, as it was never answered, I post a solution given to this problem somewhere else in case it helps someone in the future.
See the source.
select *
from TableA as a
left join TableB as b
on b.A_Id = a.A_Id
where
b.A_Id is not null or
not exists (select top 1 A_Id from TableB)
Here is another one, but you need to add one "null" row to table B if it's empty
-- In case B is empty
Insert into TableB (col1,col2) values (null,null)
select *
from TableA as a inner join TableB as b
on
b.A_Id = a.A_Id
or b.A_Id is null
I would use an if-else block to solve it like below:
if (select count(*) from tableB) > 0
begin
Select * from TableA a Inner Join TableB b on a.ID = b.A_ID
end
else
begin
Select * from TableA
end
Try This
SELECT t1.* FROM table1 AS t1 INNER JOIN table2 AS t2 ON t1.something = t2.someotherthing UNION SELECT * FROM table1 WHERE something = somethingelse;
This is solution:
CREATE TABLE MyData(Id INT, Something VARCHAR(10), OwnerId INT);
CREATE TABLE OwnerFilter(OwnerId INT);
SELECT *
FROM
(SELECT NULL AS Gr) AS Dummy
LEFT JOIN OwnerFilter F ON (1 = 1)
JOIN MyData D ON (F.OwnerId IS NULL OR D.OwnerId = F.OwnerId);
Link to sqlfiddle: http://sqlfiddle.com/#!6/0f9d9/7
I did the following:
DECLARE #TableB TABLE (id INT)
-- INSERT INTO #TableB
-- VALUES (some ids to filter by)
SELECT TOP 10 *
FROM [TableA] A
LEFT JOIN #TableB B
ON A.ID = B.id
WHERE B.id IS NOT NULL
OR iif(exists(SELECT *
FROM TableB), 1, 0) = 0
Now:
If TableB is empty (leave the commented lines commented) you'll get the top 10.
If TableB has some ids in it, you'll only join by those.
I do not know how efficient this is. Comments are welcome.
Maybe use a CTE
;WITH ctetable(
Select * from TableA
)
IF(EXISTS(SELECT 1 FROM TableB))
BEGIN
Select * from ctetable
Inner join TableB
END
ELSE
BEGIN
Select * from ctetable
END
or dynamic SQL
DECLARE #Query NVARCHAR(max);
SET #QUERY = 'Select * FROM TableA';
IF(EXISTS(SELECT 1 FROM TableB))
BEGIN
SET #QUERY = CONCAT(#QUERY,' INNER JOIN TableB');
END
EXEC sp_executesql #Query
I have a table A with the string-column a and a table B with the string-column b. a is a substring of b. Now I want to join the the two tables on a and b. Is this possible?
I want something like this:
Select * from A,B where A.a *"is substring of"* B.b
How can I write this in SQL (Transact-SQL)?
You can use like
select *
from A
inner join B
on B.b like '%'+A.a+'%'
declare #tmp1 table (id int, a varchar(max))
declare #tmp2 table (id int, b varchar(max))
insert into #tmp1 (id, a) values (1,'one')
insert into #tmp2 (id,b) values (1,'onetwo')
select * from #tmp1 one inner join #tmp2 two on charindex(one.a,two.b) > 0
You can also use charindex, 0 means its not found, greater than 0 is the start index
charindex
set an inner join on a substring(4 letters) of FIELD1 of table TABLE1 with FIELD1 of table TABLE2
select TABLE1.field1,TABLE2.field1 from TABLE1 inner join TABLE2 on substring(TABLE1.field1,2,5)=TABLE2.field1
You have the contains function:
http://msdn.microsoft.com/en-us/library/ms187787.aspx
select * from A,B where contains(B.b, A.a)
try this:
Select * from A,B where B.b LIKE '%'+A.a+'%'
Select * from A
Join B on B.b = substr(A.a, 1, 5)
The number 1 represents the first character of your string but you would pick the begin and the end of the characters you would like to match of course. Could be 5, 9 too for example.
How to compare a table against a table variable in a Stored Procedure? Normally to compare the two tables we used this query:
SELECT *
FROM Table A
WHERE NOT EXISTS(SELECT *
FROM Table B
WHERE Table A.ID = Table B.ID)
But here, I have Table A and one table variable #Item like Table B.
In this scenario, how to compare Table A and #Item?
I am writing one stored procedure, in that stored procedure I want to compare the existing one table with the table variable which is generated from the front end and passed as a XML dataset to the Stored Procedure...
In that, if all the rows in the table variable #Item presents in the existing table then it returns true else false...
Any suggestions please....
I've always preferred the left-join syntax when excluding the results of one table:
select a.*
from [table] a
left outer join #item b
on a.ID = b.ID
where b.ID is null
I suspect the query plan should come out the same though.
If works just the same (altough using table aliases will make it easier)
SELECT *
FROM Table A
WHERE NOT EXISTS(
SELECT *
FROM #Item sub
WHERE Table A.ID = sub.ID
)
Reference the table variable just like a normal table:
SELECT * FROM Table A
WHERE NOT EXISTS(SELECT * FROM #ITEM WHERE Table A.ID = #ITEM.ID)
If you're using the subquery, you can do the same sort of thing
select *
from tableA
where not in(
select b.ID
from #tableB)
the #tableB is just a table value parameter, rather than a temporary table. Its a variable that holds a table in it, so it can be passed between functions.
you might also be able to do something like:
select *
from tableA a
left outer join #tableB b
on a.ID = b.ID
where b.ID IS NULL
If you want to compare entire tables, and the schemas are guaranteed identical you can use EXCEPT.
SELECT *, 'New row' [Edit] FROM [Table A]
EXCEPT
SELECT * FROM #Item
UNION ALL
SELECT *, 'Deleted row' FROM #Item
EXCEPT
SELECT * FROM [Table A]
You should also try below using Joins as well.
SELECT * FROM Table A
Left Join #Item sub on A.ID = sub.ID
Where sub.ID is Null