SQL - Multiple Inner Join, most recent - sql

I am wondering why the below SQL query does not work properly. I am attempting to return the fields from table 1 and table 2 based on the most recent date AND only those elements in those tables that have the name Steve from a third table.
This query, meanwhile, does not actually limit the results to those with the name of Steve. If I remove the second Inner Join and focus on fields only in Table 1 to limit the universe, it works fine.
Appreciate your help on this. I am using Microsft SQL Server Management Studio.
Select *
From [db].table1
INNER JOIN [db].table2 ON table1.id=table2.id
INNER JOIN [db].table3 ON table1.id=table3.id
WHERE (table1.AsOfDate=(SELECT MAX(AsOfDate) from [db].table1))
and table3.Name = 'Steve'

The ID's may not be referring to the same ID across all three tables. Your joins assumes that is the case though. I mirrored your query with sample temp tables and your query works.
--SAMPLE TABLES
IF object_id('tempdb..#table1') is not null drop table #table1
if object_id('tempdb..#table2') is not null drop table #table2
if object_id('tempdb..#table3') is not null drop table #table3
CREATE TABLE #table1 (id INT, my_date date)
INSERT INTO #table1 (id, my_date) VALUES
(1, '1/1/2018'),
(2, '1/2/2018'),
(3, '1/1/2018')
CREATE TABLE #table2 (id INT, some_field VARCHAR(10))
INSERT INTO #table2 (id, some_field) VALUES
(1, 'abc'),
(2, 'xyz'),
(3, 'foo')
CREATE TABLE #table3 (id INT, name VARCHAR(10))
INSERT INTO #table3 (id, name) VALUES
(1, 'jon'),
(2, 'steve'),
(3, 'jane')
--QUERY
SELECT *
FROM #table1 AS x
INNER JOIN
#table2 AS y ON x.id=y.id
INNER JOIN
#table3 AS z ON z.id=x.id
WHERE x.my_date=(SELECT MAX(my_date) from #table1)
and z.name = 'Steve'
output
id my_date id some_field id name
2 2018-01-02 2 xyz 2 steve

I think the simplest way is a window function in the order by:
Select top (1) with ties . . . -- list the columns explicitly
from [db].table1 t1 join
[db].table2 t2
on t1.id = t2.id join
[db].table3 t3
on t1.id = t3.id
where t3.Name = 'Steve'
order by rank() over (order by t1.AsOfDate);

Related

SQL - How to select distinct and join multiple tables without duplicating data

I have the following table setup/data:
create table #temp (irecordid int, sdocumentno varchar(20), dtfileddate datetime, mnyconsideration money)
insert into #temp values (1, '3731572', '6-30-2014', 120.00)
Create table #temp2 (irecordid int, address varchar(255))
insert into #temp2 values (1, '406 N CUSTER')
insert into #temp2 values (1, '2015 E HANSON')
Create table #temp3 (irecordid int, srdocumentno varchar(25))
insert into #temp3 values (1, '55489')
insert into #temp3 values (1, '99809')
I am trying to select so I only get a distinct instance of each table. I am trying:
select distinct sdocumentno, address, srdocumentno
from #temp t1
join #temp2 t2 on t1.irecordid = t2.irecordid
join #temp3 t3 on t1.irecordid = t3.irecordid
And my results are as follows:
3731572 2015 E HANSON 55489
3731572 2015 E HANSON 99809
3731572 406 N CUSTER 55489
3731572 406 N CUSTER 99809
I would really like only the distinct data from each table like this:
3731572 2015 E HANSON 55489
3731572 406 N CUSTER 99809
Is there a way I can accomplish this?
Thanks!
I am guessing that you want to join on "row number", but that doesn't exist. But, you can generate one and then join on them:
select sdocumentno, address, srdocumentno
from #temp t1 join
(select t2.*,
row_number() over (partition by irecordid order by (select NULL)) as seqnum
from #temp2 t2
) t2
on t1.irecordid = t2.irecordid join
(select t3.*,
row_number() over (partition by irecordid order by (select NULL)) as seqnum
from #temp2 t3
) t3
on t1.irecordid = t3.irecordid and t2.seqnum = t3.seqnum;
You can use full outer join if the lists are of different lengths.

Update table value by adding from other table

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;

JOIN - Get one full table and the rest of another

Hi guys here is my Schema: http://sqlfiddle.com/#!4/82771
CREATE TABLE t1
(
Age INT,
Name VARCHAR(20)
);
CREATE TABLE t2
(
Age INT,
Name VARCHAR(20)
);
INSERT INTO t1(Age, Name) VALUES(31, NULL);
INSERT INTO t1(Age, Name) VALUES(32, NULL);
INSERT INTO t1(Age, Name) VALUES(33, NULL);
INSERT INTO t1(Age, Name) VALUES(34, NULL);
INSERT INTO t2(Age, Name) VALUES(31, 'Panos');
I need a Join query that will give me this Result:
Age Name
31 'Panos'
32 Null
33 Null
34 Null
I've tried LEFT JOIN and RIGHT JOIN on Age but I can't get what I need. It should be pretty simple but its just not coming to me...
maybe you have missed something when you are doing LEFT JOIN. Use also coalesce to return the first non-null value.
SELECT t1.Age, COALESCE(t2.name, t1.Name) Name
FROM t1
LEFT JOIN t2
ON t1.Age = t2.Age
SQLFiddle Demo
One way is to use union all and then check for non-existence in the second table:
select *
from t1
union all
select *
from t2
where Not exists (select 1 from t1 where t1.age = t2.age)

What's the best way to select data only appearing in one of two tables?

If I have two tables such as this:
CREATE TABLE #table1 (id INT, name VARCHAR(10))
INSERT INTO #table1 VALUES (1,'John')
INSERT INTO #table1 VALUES (2,'Alan')
INSERT INTO #table1 VALUES (3,'Dave')
INSERT INTO #table1 VALUES (4,'Fred')
CREATE TABLE #table2 (id INT, name VARCHAR(10))
INSERT INTO #table2 VALUES (1,'John')
INSERT INTO #table2 VALUES (3,'Dave')
INSERT INTO #table2 VALUES (5,'Steve')
And I want to see all rows which only appear in one of the tables, what would be the best way to go about this?
All I can think of is to either do:
SELECT * from #table1 except SELECT * FROM #table2
UNION
SELECT * from #table2 except SELECT * FROM #table1
Or something along the lines of:
SELECT id,MAX(name) as name FROM
(
SELECT *,1 as count from #table1 UNION ALL
SELECT *,1 as count from #table2
) data
group by id
HAVING SUM(count) =1
Which would return Alan,Fred and Steve in this case.
But these feel really clunky - is there a more efficient way of approaching this?
select coalesce(t1.id, t2.id) id,
coalesce(t1.name, t2.name) name
from #table1 t1
full outer join #table2 t2
on t1.id = t2.id
where t1.id is null
or t2.id is null
The full outer join guarantees records from both sides of the join. Whatever record that does not have in both sides (the ones you are looking for) will have NULL in one side or in other. That's why we filter for NULL.
The COALESCE is there to guarantee that the non NULL value will be displayed.
Finally, it's worth highlighting that repetitions are detected by ID. If you want it also to be by name, you should add name to the JOIN. If you only want to be by name, join by name only. This solution (using JOIN) gives you that flexibility.
BTW, since you provided the CREATE and INSERT code, I actually ran them and the code above is a fully working code.
You can use EXCEPT and INTERSECT:
-- All rows
SELECT * FROM #table1
UNION
SELECT * FROM #table2
EXCEPT -- except
(
-- those in both tables
SELECT * FROM #table1
INTERSECT
SELECT * FROM #table2
)
Not sure if this is any better than your EXCEPT and UNION example...
select id, name
from
(select *, count(*) over(partition by checksum(*)) as cc
from (select *
from #table1
union all
select *
from #table2
) as T
) as T
where cc = 1

write a query in sql

I have two tables that have following rows:
Table1
ID Name Number
=====================
1 a 100
2 b 200
3 c 300
Table2
ID Number Check
=====================
1 100 0
2 200 1
3 300 null
Now I want the following table:
table
---------------------
Name Number check
=====================
a 100 0
c 300 null
What query I must to write.
*You notice that the column of check in the row of 'c' in final table is null.
Thanks.
Left outer join is your friend:
select table1.name, table1.nmber, table2.check from table1 left outer join table2 on table1.nmber = table2.number
Assuming that the nmber column in table1 = number column in table2
SELECT a.name, a.nmber, b.check
FROM table1 a JOIN table2 b ON a.nmber = b.number
I believe your looking for
select a.Name, a.Nmber, b.Check
from Table1 a join table2 b
on a.Nmber = b.Number
can also add a where clase e.g.
where a.Name is not b
where b.check is not 1
etc
Hard to tell from your question how you want your results to exclude b
Set up test data.
create table table1(ID int, Name char(1), Number int)
create table table2(ID int, Number int, [Check] int)
insert into table1 values (1, 'a', 100)
insert into table1 values (2, 'b', 200)
insert into table1 values (3, 'c', 300)
insert into table2 values (1, 100, 0)
insert into table2 values (2, 200, 1)
insert into table2 values (3, 300, null)
The query
select
table1.Name,
table1.Number,
table2.[Check]
from table1
inner join table2
on table1.ID = table2.ID
where Name <> 'b'
Result
a 100 0
c 300 NULL
You must use square brackets around column name [check] because check is a reserved word. in SQL Server.
This question has been edited a lot. I believe that the answer to the original question differ from the answer to the current question.
Here is the setup for version 1 one of the question.
create table table1(ID int, Name char(1), Number int)
create table table2(ID int, Number int, [Check] int)
insert into table1 values (1, 'a', 100)
insert into table1 values (2, 'b', 200)
insert into table1 values (3, 'c', 300)
insert into table2 values (1, 100, 0)
insert into table2 values (2, 200, 1)
To get c from table1 when joined to table2 you need to use a left outer join.
select
table1.Name,
table1.Number,
table2.[Check]
from table1
left outer join table2
on table1.ID = table2.ID
where table1.Name <> 'b'
Even in this version you need the square brackets around check.