left join and get the maximum datetime value - sql-server

I have two tables ,
Table 1
Id Name
===========
1 Name1
2 Name2
3 Name3
Table 2
Id Tb1Id DateTime
=======================
1 1 20-09-2017
2 1 01-09-2018
3 2 01-09-2016
4 2 02-09-2015
5 3 06-09-2016
6 3 10-09-2019
I want to join those two tables by where Table1.Id = Table2.Tb1Id and get the maximum datetime value from Table2. The result should be like this .
Id Name DateTime
========================
1 Name1 01-09-2018
2 Name2 01-09-2016
3 Name3 10-09-2019

Try This
DECLARE #Table1 AS TABLE(Id INT,Name VARCHAR(20))
INSERT INTO #Table1
SELECT 1,'Name1' UNION ALL
SELECT 2,'Name2' UNION ALL
SELECT 3,'Name3'
DECLARE #Table2 AS TABLE(Id INT, Tb1Id INT,[DateTime] DATETIME)
INSERT INTO #Table2
SELECT 1,1,'2017-09-20' UNION ALL
SELECT 2,1,'2018-09-01' UNION ALL
SELECT 3,2,'2016-09-01' UNION ALL
SELECT 4,2,'2015-09-02' UNION ALL
SELECT 5,3,'2016-09-06' UNION ALL
SELECT 6,3,'2019-09-10'
SELECT t2.Tb1Id AS Id,
t1.Name,
MAX(t2.[DateTime]) AS [DateTime]
FROM #Table1 AS T1
INNER JOIN #Table2 AS t2
ON T1.Id = t2.Tb1Id
GROUP BY
t2.Tb1Id,
t1.Name
Result
Id Name DateTime
-----------------------------------
1 Name1 2018-09-01 00:00:00.000
2 Name2 2016-09-01 00:00:00.000
3 Name3 2019-09-10 00:00:00.000

Related

Sql Server Insert values into table based on existing rows

I have the tables tbl1 and tbl2, as shown below:
tbl1:
ID Date1 Date2
1 2020-05-11 2020-09-14
1 2020-06-13 2020-09-14
1 2020-07-15 2020-09-14
2 2020-10-01 2020-09-14
tbl1:
ID Date1 Date2 ID2
1 2020-05-11 NULL 15
1 2020-06-13 2020-10-01 15
1 2020-04-10 NULL 15
I need to insert rows into tbl2 from tbl1 if the ID and Date1 don't already exist in tbl2. My output needs to look like:
tbl2:
ID Date1 Date2 ID2
1 2020-05-11 NULL 15
1 2020-06-13 2020-10-01 15
1 2020-04-10 NULL 15
1 2020-07-15 2020-09-14 15
2 2020-10-01 2020-09-14 15
I have tried using except operator, but it doesn't work. What's the best way to do this?
Use not exists:
insert into tbl2 (id, date1, date2, id2)
select t1.id, t1.date1, t1.date2, 15
from tbl1 t1
where not exists (select 1 from tbl2 t2 where t2.id = t1.id and t2.date1 = t1.date1)
I am unclear about what you want with id2, so the above query hardcodes value 15. Maybe you want something dynamic based on available values in the target table - if so:
insert into tbl2 (id, date1, date2, id2)
select t1.id, t1.date1, t1.date2, ti.id2
from tbl1 t1
cross join (select distinct id2 from tbl1) ti
where not exists (select 1 from tbl2 t2 where t2.id = t1.id and t2.date1 = t1.date1 and t2.id2 = ti.id2)

Select all rows that has only specific value in records

I have a table that contains id, type.
I want to select all the ids that have only one or more records of the same type.
For example,
Assuming this is my table:
id type
456 4
123 4
123 4
123 18
123 4
789 4
789 4
000 7
I want to get ids: 456,789 cause those ids have only records with type = 4:
456 has one record, and 789 has two records of type = 4.
123 has type = 4, but has type = 18.
How can I do it?
I know I can use partition, but I want something like join/exists..
http://sqlfiddle.com/#!9/731e1
You can use:
SELECT id
FROM cards
GROUP BY id
HAVING MIN(type) = MAX(type)
Demo here
Select Id
FROM cards
GROUP BY Id
HAVING COUNT(DISTINCT [type]) = 1
I don't think #M.Ali answer mets your critera. His resultset includes id = '000'
if OBJECT_ID('Tempdb..#Work') is not null
drop table #Work;
Create Table #Work (Id char(3), [Type] int)
insert into #Work values
( '456', 4)
, ('123', 4)
, ('123', 4)
, ('123', 18)
, ('123', 4)
, ('789', 4)
, ('789', 4)
, ('000', 7)
select distinct *
from #Work a
where exists (
select Type
,Count(Distinct Id) cntId
from #Work b
where a.Type = b.Type
group by Type
having Count(Distinct Id) > 1
)
and exists (
select Id
,count(distinct Type)
from #Work c
where a.Id = c.Id
group by id
having count(distinct type)= 1
)
output:
Id Type
---- -----------
456 4
789 4

ORACLE Join table to select multiple record in 1 row

I have 2 tables
TableA: Main table with 1 record for each Field called ID
TableB: Can contain multiple record for field called ID
I want to select everything based on ID from TableA and TableB in 1 line for the end result
Example
Sample Records
From TableA
ID Name Address
--- ---- ----------
1 Jack 123 blahST
2 John 234 blahAVE
321 Sam 2123 blahWay
From TableB
ID AccNO
-- -------------
1 12345
1 345345
1 443453
2 99999
3 88888
3 77777
End Result should be like
Select TableA.ID,
TableA.Name,
TableA.Address,
TableB.ID,
TableB.AccNO1,
TableB.AccNO2, --if it exist
TableB.AccNO3, --if it exist
TableB.AccNO4, --if it exist MAX
From TableA Full Outer Join TableB on TableB.ID = TableA.ID
TableA.ID TableA.Name TableA.Address TableB.ID TableB.AccNO TableB.AccNO2 TableB.AccNo3,TableB.AccNo4
--------- ----------- -------------- --------- ------------ ------------- ------------- -------------
1 Jack 123 Blahst 1 12345 345345 443453
2 John 234 BlahAVE 2 99999
3 Sam 2123 Blahway 3 88888 7777777
Here are a couple of ways of doing it - one using the PIVOT keyword available in 11g and above, the other using the old-style pivot using MAX() and group by.
Method 1:
with tablea as (select 1 id, 'Jack' name, '123 blahST' address from dual union all
select 2 id, 'John' name, '234 blahAVE' address from dual union all
select 3 id, 'Sam' name, '2123 blahWay' address from dual),
tableb as (select 1 id, 12345 accno from dual union all
select 1 id, 345345 accno from dual union all
select 1 id, 443453 accno from dual union all
select 2 id, 99999 accno from dual union all
select 3 id, 88888 accno from dual union all
select 3 id, 77777 accno from dual),
b_res as (select *
from (select id,
accno,
row_number() over (partition by id order by accno) rn
from tableb)
pivot (max(accno)
for rn in (1 as accno1,
2 as accno2,
3 as accno3,
4 as accno4,
5 as accno5)))
select ta.id ta_id,
ta.name ta_name,
ta.address ta_address,
tb.id tb_id,
tb.accno1 tb_accno1,
tb.accno2 tb_accno2,
tb.accno3 tb_accno3,
tb.accno4 tb_accno4,
tb.accno5 tb_accno5
from tablea ta
inner join b_res tb on ta.id = tb.id;
TA_ID TA_NAME TA_ADDRESS TB_ID TB_ACCNO1 TB_ACCNO2 TB_ACCNO3 TB_ACCNO4 TB_ACCNO5
---------- ------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
1 Jack 123 blahST 1 12345 345345 443453
2 John 234 blahAVE 2 99999
3 Sam 2123 blahWay 3 77777 88888
Method 2:
with tablea as (select 1 id, 'Jack' name, '123 blahST' address from dual union all
select 2 id, 'John' name, '234 blahAVE' address from dual union all
select 3 id, 'Sam' name, '2123 blahWay' address from dual),
tableb as (select 1 id, 12345 accno from dual union all
select 1 id, 345345 accno from dual union all
select 1 id, 443453 accno from dual union all
select 2 id, 99999 accno from dual union all
select 3 id, 88888 accno from dual union all
select 3 id, 77777 accno from dual),
b_res as (select id,
max(case when rn = 1 then accno end) accno1,
max(case when rn = 2 then accno end) accno2,
max(case when rn = 3 then accno end) accno3,
max(case when rn = 4 then accno end) accno4,
max(case when rn = 5 then accno end) accno5
from (select id,
accno,
row_number() over (partition by id order by accno) rn
from tableb)
group by id)
select ta.id ta_id,
ta.name ta_name,
ta.address ta_address,
tb.id tb_id,
tb.accno1 tb_accno1,
tb.accno2 tb_accno2,
tb.accno3 tb_accno3,
tb.accno4 tb_accno4,
tb.accno5 tb_accno5
from tablea ta
inner join b_res tb on ta.id = tb.id;
TA_ID TA_NAME TA_ADDRESS TB_ID TB_ACCNO1 TB_ACCNO2 TB_ACCNO3 TB_ACCNO4 TB_ACCNO5
---------- ------- ------------ ---------- ---------- ---------- ---------- ---------- ----------
1 Jack 123 blahST 1 12345 345345 443453
2 John 234 blahAVE 2 99999
3 Sam 2123 blahWay 3 77777 88888

How to create a view from these 2 tables?

Table 1
bln thn qty1
1 2014 10
1 2014 20
2 2014 30
3 2014 40
2 2014 50
4 2014 60
Table 2
bln thn qty2
3 2014 200
5 2014 400
2 2014 100
2 2014 500
4 2014 300
6 2014 600
New View
bln thn qty1 qty2
1 2014 30 0
2 2014 80 600
3 2014 40 200
4 2014 60 300
5 2014 0 400
6 2014 0 600
From 2 tables at top, i'd like to create a view like table in the bottom.
Anyone would like to help ? :D thanks
I have made same Select as #JohnBevan but with some changes (not using Grouping on main select, also he forgot to name inner select columns)
DECLARE #table1 TABLE (bln INT, thn INT, qty1 INT)
INSERT INTO #table1 SELECT 1,2014,10
INSERT INTO #table1 SELECT 1,2014,20
INSERT INTO #table1 SELECT 2,2014,30
INSERT INTO #table1 SELECT 3,2014,40
INSERT INTO #table1 SELECT 2,2014,50
INSERT INTO #table1 SELECT 4,2014,60
DECLARE #table2 TABLE (bln INT, thn INT, qty2 INT)
INSERT INTO #table2 SELECT 3,2014,200
INSERT INTO #table2 SELECT 5,2014,400
INSERT INTO #table2 SELECT 2,2014,100
INSERT INTO #table2 SELECT 2,2014,500
INSERT INTO #table2 SELECT 4,2014,300
INSERT INTO #table2 SELECT 6,2014,600
CREATE VIEW NewView AS
SELECT COALESCE(T1.bln, T2.bln) AS bln
, COALESCE(T1.thn, T2.thn) AS thn
, COALESCE(T1.qty1, 0) AS qty1
, COALESCE(T2.qty2, 0) AS qty2
FROM (
SELECT bln, thn, SUM(qty1) AS qty1
FROM #table1
GROUP BY bln, thn
) AS T1
FULL JOIN (
SELECT bln, thn, SUM(qty2) AS qty2
FROM #table2
GROUP BY bln, thn
) AS T2
ON T1.bln = T2.bln
AND T1.thn = T2.thn
SQLFiddle: http://sqlfiddle.com/#!6/a3e2b/1
--create a new view called newview
create view NewView as
--if table1 has a record for this bln use it; otherwise take table 2's value
select coalesce(t1.bln,t2.bln) bln
--same for thn
, coalesce(t1.thn,t2.thn) thn
--take the sum of qty1 calculated below (max used just because we need an aggregate - they're all the same
, max(t1.qty1) qty1
--same for qty2
, max(t2.qty2) qty2
--select from the tables summing the quantities here (so we have a 1:1 match on the join / don't have to sum for every match)
from (select bln, thn, sum(qty1) as qty1 from table1 group by bln, thn) t1
full outer join (select bln, thn, sum(qty2) as qty2 from table2 group by bln, thn) t2
on t1.bln = t2.bln
and t1.thn = t2.thn
--group by the common fields so we get 1 record per value combination
group by t1.bln, t2.bln, t1.thn, t2.thn
SQLFiddle: http://sqlfiddle.com/#!6/708da/1

Pagination and INNER JOIN

I have a situation which I need to do pagination along with INNET JOIN. Here is a similar scenario I have:
DECLARE #categories AS TABLE(
CatID INT,
CategoryName NVARCHAR(100)
);
DECLARE #fooTable AS TABLE(
ID INT,
CatID INT,
Name NVARCHAR(100),
MinAllow INT,
Price DECIMAL(18,2)
);
INSERT INTO #categories VALUES(1, 'Cat1');
INSERT INTO #categories VALUES(2, 'Cat2');
INSERT INTO #categories VALUES(3, 'Cat3');
INSERT INTO #categories VALUES(4, 'Cat4');
INSERT INTO #categories VALUES(5, 'Cat5');
INSERT INTO #fooTable VALUES(1, 1, 'Product1', 2, 112.2);
INSERT INTO #fooTable VALUES(3, 1, 'Product3', 5, 233.32);
INSERT INTO #fooTable VALUES(6, 1, 'Product6', 4, 12.43);
INSERT INTO #fooTable VALUES(7, 4, 'Product7', 4, 12.43);
INSERT INTO #fooTable VALUES(8, 5, 'Product8', 4, 12.43);
These are the records I have. As you can see, some categories do not have any products inside #fooTable. As a next step, we have the following SELECT statement:
SELECT * FROM #fooTable ft
INNER JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY CatID) AS RowNum, * FROM #categories
) AS cat ON (cat.CatID = ft.CatID);
It is a basic JOIN except that the output will also carry the row number of the categories. The result I got for this query is as follows:
ID CatID Name MinAllow Price RowNum CatID CategoryName
---- ------- ------------- ----------- --------- -------- -------- -------------
1 1 Product1 2 112.20 1 1 Cat1
3 1 Product3 5 233.32 1 1 Cat1
6 1 Product6 4 12.43 1 1 Cat1
7 4 Product7 4 12.43 4 4 Cat4
8 5 Product8 4 12.43 5 5 Cat5
When you look at the RowNum column, you will see that those values are not pagination friendly. So, when I try to paginate this table as follows, I got an incorrect output:
SELECT * FROM #fooTable ft
INNER JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY CatID) AS RowNum, * FROM #categories
)AS cat ON (cat.CatID = ft.CatID) AND (cat.RowNum BETWEEN 1 AND 2);
The real situation I have is similar to this one but that query is so complicated and I need to get it working with INNER JOIN. I hope I made it clear. Any idea how I got something like that working?
Edit
According to the above result of my first select query, I should be able to retrieve products whose CatID is 1 and 4 on my second query. That's what I aim.
One solution can be the next one:
SELECT x.*
FROM
(
SELECT ft.*,
cat.CategoryName,
DENSE_RANK() OVER (ORDER BY ft.CatID) AS Rnk
FROM #fooTable ft
INNER JOIN #categories cat ON (cat.CatID = ft.CatID)
) AS x
WHERE x.Rnk BETWEEN 1 AND 2
Results:
ID CatID Name MinAllow Price CategoryName Rnk
-- ----- -------- -------- ------- ------------ ---
1 1 Product1 2 112.20 Cat1 1
3 1 Product3 5 233.32 Cat1 1
6 1 Product6 4 12.43 Cat1 1
7 4 Product7 4 12.43 Cat4 2

Resources