Update table value by adding from other table - sql

Can you please help me out with the below issue?
I have a table like below.
Table-1
Sales_RepID-- Name-- Products_Count
1-- ABC-- 2
2-- XYZ-- 4
3-- XXX-- 3
Table-2
Order_ID-- Sales_RepID-- Products_Count
1001-- 2 -- 2
1002-- 1 -- 1
1003-- 2 -- 1
1004-- 3 -- 3
1005-- 2 -- 2
Table - 1 Result
Sales_RepID, --Name, --Products_Count
1-- ABC --3
2-- XYZ --9
3-- XXX --6
I want to add table-2 Products_Count to Table-1 Products_Count for each Sale_RepID in the table-1
Can you please help with SQL Query?
My database is MS SQL SERVER

For MS SQL Server, please try:
UPDATE T
SET T.Products_Count=T.Products_Count+x.VSum
FROM Table1 T JOIN
(
SELECT DISTINCT
Sales_RepID,
SUM(Products_Count) OVER (PARTITION BY Sales_RepID) VSum
FROM
Table2
)x ON T.Sales_RepID=x.Sales_RepID

create table table1(sales_repId int,name varchar(10),product_count int);
create table table2(order_id int,sales_repId int,product_count int);
insert into table1 values(1,'ABC',2);
insert into table1 values(2,'XYZ',4);
insert into table1 values(3,'XXX',3);
insert into table2 values(1001,2,2);
insert into table2 values(1002,1,1);
insert into table2 values(1003,2,1);
insert into table2 values(1004,3,3);
insert into table2 values(1005,2,2);
select a.sales_repid,name,a.product_count+sum(b.product_count)
from table1 a
inner join table2 b
on a.sales_repid=b.sales_repid
group by a.sales_repid,name,a.product_count
order by a.sales_repid
UPDATE
update table1
set product_count = netProduct
from (
select a.sales_repid,name,a.product_count+sum(b.product_count) as netProduct
from table1 a
inner join table2 b
on a.sales_repid=b.sales_repid
group by a.sales_repid,name,a.product_count
) z
inner join table1 x
on z.sales_repid=x.sales_repid

TRY THIS
DECLARE #TABLE1 AS TABLE( Sales_RepID INT,Name VARCHAR(100), Products_Count int)
DECLARE #TABLE2 AS TABLE( Order_ID INT,Sales_RepID INT, Products_Count int)
INSERT INTO #TABLE1
VALUES(1,'ABC',2),(2,'XYZ',4),(3,'XXX',3)
INSERT INTO #TABLE2
VALUES(1001,2,2),(1002,1,1),(1003,2,1),(1004,3,3),(1005,2,2)
SELECT * FROM #TABLE1
SELECT * FROM #TABLE2
UPDATE T1
SET T1.Products_Count = T1.Products_count + total
FROM #TABLE1 T1
CROSS APPLY (
SELECT total= sum(Products_count)
FROM #Table2 T2
WHERE T1.Sales_RepID =t2.Sales_RepID ) Z

To output as a select:
select
t1.Sales_RepID,
t1.Name,
t1.Products_Count + sum(t2.Products_Count)
from table1 t1
left join table2 t2 on t2.Sales_RepID = t1.Sales_RepID
To update the total in table1, adding the total from table2:
update table1 set
Products_Count = Products_Count + (
select sum(Products_Count)
from table2
where Sales_RepID = table1.Sales_RepID)
These queries will work in all SQL dialects.
MS SQL Server has a special syntax for updating using a join, which will perform much better than the universal update syntax above:
update t1 set
t1.Products_Count = t1.Products_Count + t2.Products_Count
from table1 t1
join (select Sales_RepID, sum(Products_Count) Products_Count
from table2
group by Sales_RepID) t2
on t2.Sales_RepID = t1.Sales_RepID;
See a live demo of this update statement executing on SQLFiddle.
Note that this is an unusual query. Typically, such denormalized values are not cumulative: they are a determinable calculated value, which in this case wold be simply the sum, not the existing value plus the sum. Your design means that the query can only be executed once. After than you'll be repeatedly re-adding the total from table2.
Consider redesigning your tables to have the straight sum from table2 in table1, ie:
update t1 set
t1.Products_Count = t2.Products_Count
from table1 t1
join (select Sales_RepID, sum(Products_Count) Products_Count
from table2
group by Sales_RepID) t2
on t2.Sales_RepID = t1.Sales_RepID;

Related

SQL: JOIN problem using temp tables and one column

I am created two temp tables in which TABLE1 contains all the items and TABLE2 only has the partial list of TABLE1. How can I find out which parts TABLE 1 has that TABLE2 doesn't have or vice versa? Please keep in mind, the temp table only has one column due to the DISTINCT statement.
I do have to use Joins but my thought is if I JOIN on the individual columns of each table and then in the Where clause state that e.g. column 1 is not equal column 2, it's contradicting.
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#TABLE1')
)
BEGIN
DROP TABLE #TABLE1
END
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#TABLE2')
)
BEGIN
DROP TABLE #TABLE2
END
------------------------------------------------
select distinct 1.parts as #TABLE1 from List1 1 --- MAIN LIST
select distinct 2.parts as #TABLE2 from List2 2 --- ADDITIONAL LIST
select *
from #TABLE2 left join
#TABLE1
on 2.parts = 1.parts
where 2.parts <> 1.parts
Your where clause is undoing the left join. I would recommend not exists:
select t1.*
from #table1 t1
where not exists (select 1 from #table2 t2 where t2.parts = t1.parts);

SQL - How to get duplicate records from one table with join on another table

I want to get records from Table1 where it has more than one record for same Access Number, but at the same time this Access Number should also be present in Table2.
Example
Table1
Access Number
- 1000
- 1000
- 1000
- 2000
- 3000
- 4000
- 5000
- 5000
Table2
AccessNumber Value
- 1000 -Value1000
- 1000 -Value9999
- 2000 -Value2000
- 3000 -Value3000
The result of the query should be 1000 - Value1000
This is what I've got so far, please suggest
SELECT a.AccessNumber, b.Valuefrom Table1 a
JOIN Table2 b on b.AccessNumber = a.AccessNumber
Group by a.AccessNumber, b.VAlue
HAVING COUNT(1) > 1;
The problem i am facing is the query returns duplicates from Table2.
1000 - Value1000
1000 - Value9999
Without much information as to why 1000 - Value1000 should be the result instead of 1000 - Value9999, we can just get the first record from the top:
select top 1 * from (
-- your original query
SELECT a.AccessNumber, b.Value from Table1 a
JOIN Table2 b on b.AccessNumber = a.AccessNumber
Group by a.AccessNumber, b.Value
HAVING COUNT(1) > 1
-- your original query
) as x;
If we are just looking for the AccessNumber that has duplicate records, you can remove the b.Value from the selected columns and remove that as well in the Group By clause.
SELECT a.AccessNumber from Table1 a
JOIN Table2 b on b.AccessNumber = a.AccessNumber
Group by a.AccessNumber
HAVING COUNT(1) > 1;
http://www.sqlfiddle.com/#!18/3f114/3
We might be able to get this working using SQL Server's EXCEPT operator. But one sensible way to go here would be to just aggregate both tables by access number, and then left join the first to the second, retaining only access numbers which appear in both tables and which appear in greater quantity in the first than the second.
SELECT t1.AccessNumber
FROM
(
SELECT AccessNumber, COUNT(*) AS cnt_1
FROM Table1
GROUP BY AccessNumber
) t1
LEFT JOIN
(
SELECT AccessNumber, COUNT(*) AS cnt_2
FROM Table2
GROUP BY AccessNumber
) t2
ON t1.AccessNumber = t2.AccessNumber
WHERE
t1.cnt_1 - COALESCE(t2.cnt_2, 0) > 0 AND t2.cnt_2 IS NOT NULL;
Demo
--Hope this query will help you
; with cte_accessnumber(Accessnumber, [value])
as
(
select
t1.Accessnumber, count(*)NoOfRecords
from table1 t1
where exists (
select top 1 1 from table2 t2 where t2.Accessnumber = t1.Accessnumber)
group by t1.Accessnumber
having count(*)>1
)
select t1.Accessnumber, t2.[value]
from cte_accessnumber t1
inner join table2 t2 on t2.Accessnumber = t1.Accessnumber and t2.[value] like '%' + convert(varchar(20),t1.Accessnumber) +'%'
you may try using nested for the criteria that AccessNumber rows > 1 and cross apply for criteria which only display 1 record
DECLARE #tblA AS TABLE
(
AccessNumber INT
)
DECLARE #tblB AS TABLE
(
AccessNumber INT,
colB NVARCHAR(50)
)
INSERT INTO #tblA SELECT 1000
INSERT INTO #tblA SELECT 1000
INSERT INTO #tblA SELECT 1000
INSERT INTO #tblA SELECT 1000
INSERT INTO #tblA SELECT 2000
INSERT INTO #tblA SELECT 3000
INSERT INTO #tblA SELECT 4000
INSERT INTO #tblB SELECT 1000,'hello'
INSERT INTO #tblB SELECT 1000,'hello2'
INSERT INTO #tblB SELECT 2000,'world'
-- Query --
SELECT tblB.* FROM (
SELECT AccessNumber,COUNT(1) AS cnt FROM #tblA GROUP BY AccessNumber ) ftblA
CROSS APPLY (SELECT TOP(1) * FROM #tblB itblB WHERE ftblA.AccessNumber = itblB.AccessNumber) tblB
WHERE ftblA.cnt >1
-- Only 1000 should be displayed only --
Use subquery with correlation approach
select access_no,
(select top 1 Value from table2 where access_no = t.access_no) as value
from Table1 t
where exists (
select 1 from table2 where access_no = t.access_no)
group by access_no
having count(*) > 1
However, you would need to specify order by clause in subquery in order to fetch the value from table2

Find Set of record rowno from multiple column

I have two sql temp table #Temp1 and #Temp2, and I want to get rowid which contain set of temp table two
E.g. In table Temp2 have 4 record i want to search in temp table #Temp1 which contain userid departmentid set of record
CREATE TABLE #Temp1(rowid INT, userid INT, departmentid int)
CREATE TABLE #Temp2(userid INT, deparetmentid int)
INSERT INTO #Temp1 (rowid,userid,departmentid )
VALUES (1,1,1),(1,2,2),(1,3,3),(1,4,4),(1,2,1),
(2,2,1),(2,2,2),(2,3,3),(2,4,4),
(3,3,1),(3,2,2),(3,3,3),(3,4,4)
INSERT INTO #Temp2 (userid,departmentid )
VALUES (2,1),(2,2),(3,3),(4,4)
DROP TABLE #Temp1
DROP TABLE #Temp2
i want output rowid 2 because it contain set of (2,1),(2,2),(3,3),(4,4)
one thing in rowid also contain same set of record it its have one more row mean
when i search in temp1 table based on rowid 1 then i found 4 record and when i search rowid 2 then it contain 4 record so that it is same set of record which i found
Thanks
You could use:
SELECT rowid
FROM #Temp1 t1
WHERE NOT EXISTS(SELECT userid, departmentid
FROM #Temp1 tx
WHERE tx.rowid=t1.rowid
EXCEPT
SELECT userid, departmentid
FROM #Temp2)
GROUP BY rowid
HAVING COUNT(*) = (SELECT COUNT(*) FROM #Temp2);
Output:
2
Rextester Demo
Let's assume the rows in table1 are unique. Then you can do this using join and group by:
select t1.rowid
from #table1 t1 left join
#table2 t2
on t1.userid = t2.userid and t1.departmentid = t2.departmentid
group by t1.rowid
having count(*) = (select count(*) from #table2 t2) and
count(*) = count(t2.userid) ;
This assumes no duplicates in either table.
Note: This returns rows that are identical to or a superset of the values in the second table.

SQL Join on partial column data (SQL Server)

Both columns are tinyint if it matters.
Table1
Version
--------
111115
222226
333337
Table2
ID Year
--------
5 2015
6 2016
7 2017
I need to join on the ID from table 2 if it equals the last value in the version field from table 1.
Version 111115 would join to ID 5. I know how to select on things like this but is joining feasible? The result being:
111115 5 2015
TIA!
You can use the RIGHT() function to do this:
SELECT *
FROM Table1 A
INNER JOIN Table2 B on RIGHT(A.Version,1) = B.ID
I would probably avoid having to do this very much though. It is a faulty database design. Perhaps add a column ID to table 1, and use:
UPDATE Table1
SET ID = RIGHT(Version,1)
Since they are both integer, you can try the modulus operator. It takes the remainder after division. So 111115 % 10 is 5.
SELECT *
FROM Table1 t1
INNER JOIN Table2 t2 on t1.Version % 10 = t2.ID
Declare #tblTest as table
(
id INT,
yearName INT
)
Declare #tblVersion as table
(
VersionNo INT
)
INSERT INTO #tblTest values(5,2015)
INSERT INTO #tblTest values(6,2016)
INSERT INTO #tblTest values(7,2017)
INSERT INTO #tblVersion values(111115)
INSERT INTO #tblVersion values(111116)
INSERT INTO #tblVersion values(111117)
select
*,RIGHT(VersionNo,1)
from #tblVersion
SELECT
*
FROM #tblTest T1
LEFT JOIN (SELECT RIGHT(VersionNo,1) AS VersionId,VersionNo FROM #tblVersion) T2 ON T2.VersionId=T1.id

Case statement trickery required

Table 1
Mail Special Quote (Y/N)
g#hotmail.com Blank
s#ho.com Blank
sss#j.com Blank
Table 2
Email Address Dept
g#hotmail.com Config
s#ho.com Finance
sss#j.com Marketing
Now I want Table 1 updated to Y where the matching email address in Table 2 is coming from Finance or Marketing .
UPDATE TABLE 1
Set Special Quote to be Y
where in TABLE 2 the Dept is Finance or Marketing for the matching email address.
Probably just having a brain freeze and need some coffee .
Thinking left join on email address then throw in a bit of a case statement perhaps for the Y and N bit ?
no case statement needed.
update table1 set special_quote = 'Y'
where mail in ( select email_address from table2 where dept in ('Finance','Marketing' ))
Try the following:
UPDATE A
SET A.SpecialQuote = 'Y'
FROM Table1 A
INNER JOIN Table2 B
ON A.Mail = B.EmailAddress
WHERE B.Dept IN ('Finance','Marketing')
I'm more of a MySQL user so this could be wrong, but try something like this:
UPDATE table1 SET specialquote = 'Y'
WHERE Mail IN (SELECT EmailAddress FROM table2 WHERE Dept IN ('Finance','Marketing'))
You were very close, you will need to join the two tables on the mail field but then check if the Dept is in Finance/Marketing
UPDATE t1
SET t1.[Special Quote] = 'Y'
FROM Table1 t1
INNER JOIN Table2 t2
ON t1.mail = t2.mail
WHERE t2.Dept in ('Finance','Marketing')
This will update only the items that are included, if you want to update either Y/N, then you could do the following (see SQL Fiddle with Demo)
UPDATE t1
SET t1.sq = CASE WHEN t2.dept IS NOT NULL THEN 'Y' ELSE 'N' END
FROM table1 t1
LEFT JOIN table2 t2
ON t1.mail = t2.mail
AND t2.Dept in ('Finance','Marketing')
You are on the right track. Here is the syntax:
update table1
set SpecialQuote = 'Y'
where mail in (select emailaddress from table2 where dept in ('Finance', 'Marketing')
create table #tbl1 (mail varchar(50),quote varchar(1))
create table #tbl2 (mail varchar(50),dept varchar(10))
insert into #tbl1 values ('a#a.com','')
insert into #tbl1 values ('b#b.com','')
insert into #tbl1 values ('c#c.com','')
insert into #tbl1 values ('d#d.com','')
insert into #tbl1 values ('e#e.com','')
insert into #tbl2 values ('a#a.com','config')
insert into #tbl2 values ('b#b.com','finance')
insert into #tbl2 values ('c#c.com','marketing')
insert into #tbl2 values ('d#d.com','other')
insert into #tbl2 values ('e#e.com','skivers')
update #tbl1
set quote = 'Y'
where mail in (SELECT mail FROM #tbl2 WHERE dept IN ('finance','marketing'))
select * from #tbl1
drop table #tbl1
drop table #tbl2
I like to use CTEs to help clarify different pieces of a query, so here is one way to do this. There are others if you don't like it.
with getval as (
select mail,dept from test2
where dept in ('Marketing','Finance')
)
update test1
set quote = case when dept is NOT null then 'Y' else 'N' end
from test1 t1
left outer join getval t2 on t1.mail = t2.mail
Anyway, I used a left join to take all of the records, then used a case to sort where the dept appeared (meaning the record was found in the CTE).
OR...
update table1
set quote = case when dept is NOT null then 'Y' else 'N' end
from table1 t1
left outer join table2 t2 on t1.email = t2.email and t2.dept in ('Marketing','Finance')
That should also work.
Update Table1
Set [Special Quote]='Y'
from Table1 t1
join Table2 t2
on t1.[Email Address]=t2.[Email Address]
where t2.dept in ('Finance','Marketing')
Untested sample, so understand that caveat, but believe it is close enough to illustrate the point. Good luck!
EDIT: Per the OP's "Y/N update" comment below, change as follows...although there are several other subtly different ways you could accomplish the same thing. Hope this helps you.
Update Table1
Set [Special Quote]=(case when t2.dept='Finance'
then 'Y'
when t2.dept='Marketing'
then 'Y'
else 'N'
end)
from Table1 t1
join Table2 t2
on t1.[Email Address]=t2.[Email Address]