TSQL update value with subquery - sql-server

I have 2 tables and want to compare them and modify tableA (set NameMod = 1) if it has different rows.
To compare tables I use:
select Id, Name from tableB
except
select Id, Name from tableA
And then I want to modify tableA:
update tableA Set NameMod = 1
where exists (
select Id, Name from tableB
except
select Id, Name from tableA
)
But I can only use EXISTS before the sub-query and in this case it updates all elements in table not different rows.

Could you try this:
MERGE TableA AS [Target]
USING TableB AS [Source]
ON [Target].[ID] = [Source].[ID]
AND [Target].[Name ] = [Source].[Name]
WHEN NOT MATCHED BY TARGET
THEN UPDATE SET NameMod = 1;
It is using the MERGE clause.
If you do not like the clause, you can use CTE like this:
;WITH IdsForUpdate ([id]) AS
(
SELECT DISTINCT Id
FROM
(
select Id, Name from tableB
except
select Id, Name from tableA
) DS([id], [name])
)
update tableA
Set NameMod = 1
FROM tableA A
INNER JOIN IdsForUpdate B
ON A.[id] = B.[id];

Related

sql query to get the address of customer

I have two tables i.e. table A and table B. Table B has primary key of table A as Id column.
I want to get the name and address from two tables.
How can I achieved this?
I tried:
select name,address from tableA join tableB on tableA.id=tableB.id
Your own answer is correct.
Here's the tables you described with the relationships:
I filled the tables with some guid's and copy pasted your own SQL
(50 rows affected)
Try this
Check tableA has values
Select COUNT(*) from [tableA]
And tableB
Select COUNT(*) from [tableB]
if they both have a count > 0
How many items in tableA have at least one value in tableB
--Show all the raw data
Select tableA.*,(select count(*) from tableB where tableA.id = tableB.id)VolumeOfAddresses
FROM tableA
--or Group and count it
Select VolumeOfAddresses,count(*) NameCount
FROM (Select tableA.*,(select count(*) from tableB where tableA.id = tableB.id)VolumeOfAddresses
FROM tableA) a
group by a.VolumeOfAddresses
--or express that as a string of text for simplicity
Select cast(count(*) as varchar(10)) + ' Names exists which each have an address COUNT of ' + cast(VolumeOfAddresses as varchar(10))A_TextString
FROM (Select tableA.*,(select count(*) from tableB where tableA.id = tableB.id)VolumeOfAddresses
FROM tableA) a
group by a.VolumeOfAddresses
The example result from the last query in my testing shows:
50 Names exists which each have an address COUNT of 0
50 Names exists which each have an address COUNT of 1

SQL IN clause multiple columns and multiple value

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.

SQL Server : how to check if a row exist in other tables

I would like to ask for help if how can I write a T-SQL query that checks if a row exists in other tables and insert the data in a temporary table.
For example, I have 5 tables main1, table2, table3, table4 and table5. Each table has a product_id column.
I need main1.product_id (values A000 to A010) to check if they exist in table2, table3, table4 and table5.
If it is found in table2, the value "A000" will be inserted into a temporary table. If it is not found, it will check in table3; again if not found, it will check in table4.
Then main1.product_id value "A001" will be checked. If A001 is found in table2 it won't be checked in table3 and table4 anymore, it will be written into the temp table and next value is to be checked from main1 table, and so on,...
Thanks so much
Looks like you're looking for something like this:
insert into #tmp
select product_id
from main1 m
where
(
exists (select 1 from table2 t where t.product_id = m.product_id)
or exists (select 1 from table3 t where t.product_id = m.product_id)
or exists (select 1 from table4 t where t.product_id = m.product_id)
or exists (select 1 from table5 t where t.product_id = m.product_id)
)
This will check each of the tables, and if the row is found, inserts it into #tmp
Or, alternatively, you could just use UNION ALL like in
Insert into #tmp
Select product_id from main1 where exists
(select 1 from (
select product_id p from table2 union all
select product_id from table3 union all
select product_id from table4 union all
select product_id from table5
) all where p=product_id )

T-SQL Insert when not in table and when max timestamp Issue

I am trying to insert rows from one table to another that are not in the one I am moving them to. I also want to only move the ones that have the highest datestamp. (I want to only insert rows that are not in tb1 and have the max timestamp)
This is what I have so far:
INSERT INTO [db].[dbo].[tb1]
SELECT *
FROM tb2
WHERE ( dbo.tb2.STime = (SELECT Max(STime)
FROM dbo.tb2) )
AND ( EMPNO NOT IN (SELECT EMPNO
FROM [db].[dbo].[tb1]) );
I Get this error when I execute:
Msg 147, Level 15, State 1, Line 43 An aggregate may not appear in the
WHERE clause unless it is in a subquery contained in a HAVING clause
or a select list, and the column being aggregated is an outer
reference.
-EDIT
RESOLVED
WITH aggregateTime (maxTime) AS (
SELECT MAX(STime) AS maxTime
FROM tb2
)
INSERT INTO db.dbo.tb1
SELECT *
FROM tb2
INNER JOIN aggregateTime ON 1=1
WHERE tb2.STime = aggregateTime.maxTime AND EMPNO NOT IN (SELECT EMPNO FROM tb1);
You could use a CTE with just one column that is the maxtime from tb2. Then join on the CTE and reference it when checking for if its the max or not.
WITH aggregateTime (maxTime) AS (
SELECT MAX(STime) AS maxTime
FROM tb2
)
INSERT INTO tb1 (id, EMPNO, Street1)
SELECT id, EMPNO, Street1
FROM tb2
INNER JOIN aggregateTime ON 1=1
WHERE tb2.STime = aggregateTime.maxTime AND EMPNO NOT IN (SELECT EMPNO FROM tb1);
Working SQL Fiddle: http://sqlfiddle.com/#!6/141bf/4

TSQL foreach record join a cte and insert

I need to create a SQL-Query that uses a recursive CTE to fetch records from TableA. (Tree-Structure). I pass him the "leaf" and want to know the way back to the root.
This works with a #SOME_ID Variable
;WITH cte_recursive AS
(
SELECT ID, SUB_ID FROM tableA
WHERE SUB_ID = #SOME_ID
UNION ALL
SELECT parent.ID, parent.SUB_ID
FROM tableA parent
INNER JOIN cte_recursive child ON child.ID = parent.SUB_ID
)
What I need to acchieve now is, that I take every record from TableB
and use tableB.SOME_ID for the CTE Expression and create an insert into TableC foreach record the CTE generates plus some fields from TableB
(cte_recursive.CHILD_ID, tableB.SomeValue, tableB.SomeOtherValue)
So my question here is, how do I pass the tableB.SOME_ID to the cte expression ?
So in TableA I got something like this:
ID, SUB_ID
1 , 2
2 , 3
2 , 4
2 , 5
5 , 6
7 , 8
8 , 9
If I pass him SUB_ID = 5, the CTE returns me the Records #1, #2, #3, #4, #5
as SUB_ID = 5 is a Child of a Child of a child... of ID = 1
You can create table valued function
create function ftBranchOf
(
#SOME_ID int -- actual type of #SOME_ID
)
returns table as return
(
WITH cte_recursive AS
(
SELECT ID, SUB_ID FROM tableA
WHERE SUB_ID = #SOME_ID
UNION ALL
SELECT parent.ID, parent.SUB_ID
FROM tableA parent
INNER JOIN cte_recursive child ON child.ID = parent.SUB_ID
)
select * from cte_recursive
)
And then use it in your query
insert into TableC (...)
select p.ID, b.SomeValue, b.SomeOtherValue
from TableB b
cross apply ftBranchOf(b.SOME_ID) p
I'm not sure what are you want, so just guessing
;WITH cte_tableB AS
(
SELECT * FROM tableB
)
, cte_recursive AS
(
SELECT ID, SUB_ID, SOME_ID FROM tableA
WHERE SUB_ID IN (SELECT SOME_ID FROM cte_tableB)
UNION ALL
SELECT parent.ID, parent.SUB_ID, SOME_ID
FROM tableA parent
INNER JOIN cte_recursive child ON child.ID = parent.SUB_ID
)
INSERT [YourTable] ([YourColumns...])
SELECT [YourColumns...]
FROM cte_recursive
INNER JOIN cte_tableB ON cte_recursive.SomeID = cte_tableB.SomeID

Resources