Microsoft SQL - Update while Select - sql-server

is there any way to update while selecting data to avoid extra accesses?
We select 2500 datasets and need to set a value to 1 while we do this, current solution WOULD be to do it in the profile, 1 by 1, which leads to 2500 accesses to the database...

You can turn your SELECT query into an UPDATE easily.
I don't know what your SELECT looks like, but you could follow this pattern:
SELECT
c.column1
, b.column2
, a.column3
FROM Table1 a
INNER JOIN Table2 b
ON a.PK = b.FK
INNER JOIN Table3 c
ON b.PK = c.FK
WHERE a.column4 = 'a'
AND b.column4 = 'x'
to
UPDATE a
SET column3 = 1
, column4 = 'b'
FROM Table1 a
INNER JOIN Table2 b
ON a.PK = b.FK
INNER JOIN Table3 c
ON b.PK = c.FK
WHERE a.column4 = 'a'
AND b.column4 = 'x'
This will do 1 database access and do all the work.

Related

Is it possible to inner join a different table based on a sproc parameter?

I'm in charge of a legacy project and I was looking at simplifying or streamlining a bit.
What I want to do is something like:
declare #n int = 1
select * from table_a a
case when #n = 1 then inner join table_b b on b.x = a.x
else inner join table_c c a.x = c.x
end
The main reason I'm hoping this is possible is because I'm trying to get rid of a lot of repetition in the current sproc. Every time something changes, we have to make sure that each section is updated appropriately.
Currently it looks something like:
if #a = 1 begin
select (long list of columns but not all) from table_A
inner join table_2 a on table_A.a = table_2.a
left join table_B on table_A.c = table_B.c
where (several conditions here)
end
else if #= 2 begin
select (same long list of columns) from table_A
inner join table_3 a on table_A.a = table_3.a
left join table_B on table_A.c = table_B.c
where (same several conditions)
end
else
select (same list again) from table_A
inner join table_4 a on table_A.a = table_4.a
left join table_B on table_A.c = table_B.c
where (same conditions again)
end
In the example, tables 2, 3, and 4 are essentially identical as far as columns are concerned but are used to separate groups.
If it's not possible, I'm thinking I could combine all three of those tables into a single table and add a new column denoting the group and then inner join on that column along with the other one. I just figured that I'd rather not move data around if I didn't have to.
A variation of the following technique can be used, I'm using an outer join with null check.
declare #myVar int
set #myVar = 1
select
t1.id,
t1.nm,
coalesce(t2.nm, t3.nm) valu
from
table1 t1
left outer join
table2 t2 on (t1.id = t2.id and #myVar = 1)
left outer join
table3 t3 on (t1.id = t3.id and #myVar = 2)
where coalesce(t2.nm, t3.nm) is not null
The basic made-up schema in use:
select *
into table1
from
(select 1 id, 'a' nm union
select 2, 'b' union
select 3, 'c' union
select 7, 'j') a
select *
into table2
from
(select 1 id, 'a1' nm union
select 2, 'b1' union
select 3, 'c1' union
select 4, 'd1' ) a
select *
into table3
from
(select 1 id, 'a2' nm union
select 2, 'b2' union
select 3, 'c2' union
select 4, 'd2' union
select 5, 'e2' ) a
Does this work for you?
You can use an CROSS APPLY(...UNION ALL...) to effectively implement a conditional join to your middle table.
select (long list of columns but not all)
from table_A
cross apply (
select t2.c from table_2 t2 where t2.a = table_A.a and #a = 1
union all
select t3.c from table_3 t3 where t3.a = table_A.a and #a = 2
union all
select t4.c from table_4 t4 where t4.a = table_A.a and #a not in (1,2)
) X
left join table_B on X.c = table_B.c
where (several conditions here)
This should even run quite efficiently, assuming that you have indexes on table_2.a, table_3.a, table_4.a, and table_B.c.

How to use inner join and left join for two tables in same query using T-SQL

Given two tables:
tblBase - database table (code_no, empid)
#type_temp is a temporary user defined table which will come from vb.net frontend (code_no, name)
Firstly I need to get code_no which are in #type_temp and not in tblBase.
Query:
select
t.code_no, 'Non-existing' as Remark
from
#type_temp t
left join
tblBase b on t.code_no = b.code_no
where
b.code_no is null
Next I need to get all code_no that have empid = 1.
Query :
select
t.code_no, 'Existing' as Remark
from
#type_temp t
inner join
tblBase b on t.code_no = b.code_no
where
b.empid = 1
I need to use both these queries together.
Currently I'm using union to club the two.
select
t.code_no, 'Non-existing' as Remark
from
#type_temp t
left join
tblBase b on t.code_no = b.code_no
where
b.code_no is null
union
select
t.code_no, 'Existing' as Remark
from
#type_temp t
inner join
tblBase b on t.code_no = b.code_no
where
b.empid = 1
I do not want union here. Any other alternative possible?
Does this work for you?
SELECT type_temp.code_no
, CASE WHEN tblBase.code_no IS NULL THEN 'Non-existing' ELSE 'Existing' END AS Remark
FROM #type_temp AS type_temp
LEFT
JOIN tblBase
ON tblBase.code_no = type_temp.code_no
WHERE tblBase.empid = 1
OR tblBase.code_no IS NULL
;
An even better option than #gvee's answer, is to put the conditions into the ON clause
SELECT
type_temp.code_no,
CASE WHEN tblBase.code_no IS NULL THEN 'Non-existing' ELSE 'Existing' END AS Remark
FROM #type_temp AS type_temp
LEFT JOIN tblBase ON tblBase.code_no = type_temp.code_no
AND tblBase.empid = 1;
This is likely to be more performant, as the join is pre-filtered.

sql query to get record by multiple values

I need a sql query that can get records from multiple table. Please check the scenario below -
There are 2 tables - Table1 and Table2
Below is the query.
Table1 :
PID PName
1 A
2 B
Table2 : (There is a foreign key relationship b/w Table1 and Table2 by 'PID')
PPID PID RID
101 1 222
102 1 333
103 2 001
104 2 002
And I want query that can get records from Table1 (I need PName) and Table2 like that-
SELECT t1.PName FROM Table1
INNER JOIN Table2 on t1.PID = t2.PID
where t2.PID = '222' and t2.PID = '333'
or
SELECT t1.PName FROM Table1
INNER JOIN Table2 on t1.PID = t2.PID
INNER JOIN dbo.StringSplit('222,333', ',') AS t on t2.PID = t.item
But in both cases I am not getting the correct resutl.
I want records where PID should exists for both RID's like - 222 and 333
The output should be like this -
PName
A
Can anyone help me out on this ?
This is a common question. It is easy to do with grouping:
select min(PName) as PName
from Table1 t1 inner join Table2 t2 on t2.PID = t1.PID
where t2.RID in ('222', '333')
group by t1.PID
having count(*) = 2
Your sample data is limited and it's not clear what is the significance of the special values "111" and "222". Depending on the actual relationship you may really want a variation like count(*) >= 2 or count(distinct t2.RID) = 2 instead.
Btw, a few of the other answer are using a left join and then filtering on the inner table afterward in the where clause. In general that would be incorrect but in your case it wouldn't change your results because the outer join isn't relevant in the first place. Whichever solution you select, don't use an outer join here.
Your first query will always return 0 results as t2.PID cannot equal both 222 and 333.
If I understand your question correctly, you want to include results where PID is 222 OR 333. E.g.
SELECT t1.PName, t2.RID FROM Table1
INNER JOIN Table2 on t1.PID = t2.PID
where t2.PID = '222' OR t2.PID = '333'
You need to use LEFT JOIN:
SELECT t1.PName, t2.RID FROM Table1 t1
LEFT JOIN table2 t2
ON t1.PID = t2.PID
WHERE t2.RID = '222' OR t2.RID = '333'
You could use distinct
SELECT DISTINCT PNAME FROM dbo.Table1
INNER JOIN dbo.Table2 ON Table11.PID = TABle22.PID
WHERE rid IN ('222','333')

Not in Not exists

I have three tables
table1 -> xt1, yt1, zt1;
table2 -> xt2
table3 -> yt3, zt3
SELECT xt1, yt1, zt1
From table1, table3
Where xt1
NOT IN
(SELECT DISTINCT table1.xt1 FROM table2 INNER JOIN table1 ON
table1.xt1 = Replace(table2.xt2,',',''))
And table1.yt1 = table3.yt3
AND table1.zt1 = table3.zt3
it is working correctly but i take long time.
if i replace NOT IN with Not exists it return empty set.
SELECT xt1, yt1, zt1
From table1, table3
Where Not exists
(SELECT DISTINCT table1.xt1 FROM table2 INNER JOIN table1 ON
table1.xt1 = Replace(table2.xt2,',',''))
And table1.yt1 = table3.yt3
AND table1.zt1 = table3.zt3
the results of the second select should be 6 rows but it returns notiong with not exists.
also if i tried to change the compare part to
table1.xt1 != Replace(table2.xt2,',','') and remove the NOT IN
select it get outof memory error.
So is this the best way to write my query and why it return empty set with Not exists
thank you.
Ok, first of all, I changed your implicit join to an explicit one. Then I fixed the NOT EXISTS so it correlates to the outer table1:
SELECT t1.xt1, t1.yt1, t1.zt1
FROM table1 AS t1
INNER JOIN table3 AS t3
ON t1.yt1 = t3.yt3
AND t1.zt1 = t3.zt3
WHERE NOT EXISTS ( SELECT 1
FROM table2 AS t2
INNER JOIN table1 AS t1_1
ON t1_1.xt1 = REPLACE(t2.xt2,',','')
AND t1_1.xt1 = t1.xt1) ;
which can be simplified further to:
SELECT t1.xt1, t1.yt1, t1.zt1
FROM table1 AS t1
INNER JOIN table3 AS t3
ON t1.yt1 = t3.yt3
AND t1.zt1 = t3.zt3
WHERE NOT EXISTS ( SELECT 1
FROM table2 AS t2
WHERE t1.xt1 = REPLACE(t2.xt2,',','')
) ;
You need to select IN or exist depending upon the size of inner query. when there is a outer query and inner-sub-query, if the result of sub query is small, In is preferred as outer query is selected based upon result of sub-query.
if the result of sub-query is large, exist is preferred as outer query is evaluated first.

which one is better:Filter on join clause or Filter on where clause when joining two table?

I am trying to join 2 or more tables on MS SQL Server. All the tables have IsActive field which determines the active record. (IsActive = 1 means active record and IsActive = 0 means inactive record or record has been deleted from system)
So I have two conditions for joining the two or more tables.
On The first query,I filter the IsActive on the join clause
select * from table_A a
inner join table_B b
on a.ID = b.ID and b.IsActive = 1
inner join table_C c
on b.ID = c.ID and c.IsActive = 1
where a.IsActive = 1
On The second query, I also can filter IsActive on the where Clause
select * from table_A a
inner join table_B b
on a.ID = b.ID
inner join table_C c
on b.ID = c.ID
where a.IsActive = 1 and b.IsActive = 1
and c.IsActive = 1
notes: The relation from table A to B is one to one but from table A to C is one to many and also all the table has clustered index on primary key ID and the ID is auto increment.
So which one do you think is better? (assume each table has approximately 100.000 records (80% active records and 20% inactive records))
Thanks
The difference is simple but takes a careful eye to spot.
Consider the following example:
create table tbl_client as
select 1 as client_id, 'aaa' as client_name, 'Y' is_active from dual
union all
select 2, 'bbbbb', 'N' from dual
union all
select 3, 'cc', 'Y' from dual;
create table tbl_transaction as
select 1 transaction_id, 1 client_id, 123.34 amount from dual
union all
select 2, 1, 4353.45 from dual
union all
select 3, 2, 251.48 from dual;
Now, on these tables run the followoing queries:
Inner Join:
In an inner join, there is no difference in the results of the following two queries:
select c.client_name, t.amount, t.is_paid
from tbl_client c
inner join tbl_transaction t
on c.client_id = t.client_id
and t.is_paid = 'Y'; -- filter on join
select c.client_name, t.amount, t.is_paid
from tbl_client c
inner join tbl_transaction t
on c.client_id = t.client_id
where t.is_paid = 'Y'; -- filter in where
Both their result is the same as:
CLIENT_NAME AMOUNT IS_PAID
----------- ---------- -------
aaa 123.34 Y
aaa 4353.45 Y
Left Outer Join
This is where the difference kicks in.
Consider the following query:
select c.client_name, t.amount, t.is_paid
from tbl_client c
left outer join tbl_transaction t
on c.client_id = t.client_id
and t.is_paid = 'Y'; -- << filter in join
Result:
CLIENT_NAME AMOUNT IS_PAID
----------- ---------- -------
aaa 123.34 Y
aaa 4353.45 Y
cc -- << Note that client cc's transaction record is not there
bbbbb -- << and this client also shows up
And when you apply filter on where in a left outer join:
select c.client_name, t.amount, t.is_paid
from tbl_client c
left outer join tbl_transaction t
on c.client_id = t.client_id
where t.is_paid = 'Y'; -- << filter in where
Result:
CLIENT_NAME AMOUNT IS_PAID
----------- ---------- -------
aaa 123.34 Y
aaa 4353.45 Y -- No row for bbbbb or cc clients, just like the inner join
Summary
In short, when you put a filter on the joining condition, the filter is applied to the table being joined. For example, in the first case in the left outer join section, the row for tbl_transaction didn't show up for the client bbbbb.
But when you put a filter in the where clause, it filters the entire data set that is retrieved after joining all the tables (logically. Internal technical operations differ across RDBMSes). This is why the rows for bbbbb and cc didn't show up in the last query.
Fiddle
EDIT
As #DanGuzmanSqlServerMvp has mentioned in his comment, for the example you have posted in your question, the SQL Server query optimizer should execute the same plan. However, if there was an outer join in your query, the plans would be different.

Resources