repeatation on output result according date insqlserver - sql-server

Concatenate values from multiple columns of 3 tables and display in one column. Date field is datetime.now my problem is if date is repeat of one table then amt2,amt3 is also repeat on same date
table1:
date amt1
1-1-2016 10:44:00 111
1-1-2016 10:44:02 222 repeat date
3-4-2016 11:44:00 111
table2:
date amt2
1-1-2016 10:44:02 101
2-2-2016 10:44:02 333
2-3-2016 10:44:02 444
table3:
date amt3
2-2-2016 10:44:04 001
2-3-2016 10:44:02 002
3-3-2016 10:44:02 003
query
SELECT
COALESCE(t1.date, t2.date, t3.date)
, t1.amt1
, t2.amt2
, t3.amt3
FROM tb_amount t1
FULL JOIN tb_cashamt t2 ON t1.date =t2.date
FULL JOIN tb_grandtotal t3 ON t2.date = t3.date
output:
date amt1 amt2 amt3
1-1-2016 10:44:00 111 null NULL
1-1-2016 10:44:02 111 101 null data repeat on amt1(111)
2-2-2016 10:44:02 NULL 333 null
2-2-2016 10:44:04 NULL 333 001 data repeat on amt2(111)
TOTAL --- --- -----
Desired output:
date amt1 amt2 amt3
1-1-2016 111 101 NULL
2-2-2016 NULL 333 001
TOTAL total(amt1) total(amt1) total(amt1)
I have problem with smalldatetime datatype on datecolumn. I want a result on each date and amt1,amt2,amt3 show total data on this date

Use FULL JOIN
SELECT
COALESCE(t1.date, t2.date, t3.date)
, t1.amt1
, t2.amt2
, t3.amt3
FROM Table1 t1
FULL JOIN Table2 t2 ON t1.date =t2.date
FULL JOIN Table3 t3 ON t2.date = t3.date

You'll need to use the FULL JOIN, also known as FULL OUTER JOIN as explained on Using Outer Joins:
To retain the nonmatching information by including nonmatching rows in the results of a join, use a full outer join. SQL Server provides the full outer join operator, FULL OUTER JOIN, which includes all rows from both tables, regardless of whether or not the other table has a matching value.
;
WITH Table1 AS
( SELECT [Date], Amt1
FROM ( VALUES
('2016-01-01', 111),
('2016-02-02', 222),
('2016-04-03', 111)
) AS Table1(Date, Amt1)
), Table2 AS
( SELECT [Date], Amt2
FROM ( VALUES
('2016-01-01', 101),
('2016-02-02', 333),
('2016-03-02', 444),
('2016-03-03', 456),
('2016-04-01', 101),
('2016-04-03', 111)
) AS Table2(Date, Amt2)
), Table3 AS
( SELECT [Date], Amt3
FROM ( VALUES
('2016-02-02', 001),
('2016-03-02', 002),
('2016-03-03', 003),
('2016-04-01', 555),
('2016-04-02', 666),
('2016-04-03', 777)
) AS Table3(Date, Amt3)
)
SELECT ISNULL(Table1.Date, ISNULL(Table2.Date, Table3.Date)) Date,
Table1.Amt1, Table2.Amt2, Table3.Amt3
FROM Table1
FULL JOIN Table2 ON Table1.Date = Table2.Date
FULL JOIN Table3 ON Table2.Date = Table3.Date
ORDER BY ISNULL(Table1.Date, ISNULL(Table2.Date, Table3.Date))

If you need only one row per date, you need to group by + sum each of the tables on date level first before joining + you can use rollup for the total:
select coalesce(T1.Date,T2.Date,T3.Date), sum(T1.Amt1),Sum(T2.Amt2),Sum(T3.Amt3)
from
(
select convert(date, date) as Date, sum(Amt1) as Amt1
from Table1
group by convert(date, date)
) T1
full outer join (
select convert(date, date) as Date, sum(Amt2) as Amt2
from Table2
group by convert(date, date)
) T2 on T1.Date = T2.Date
full outer join (
select convert(date, date) as Date, sum(Amt3) as Amt3
from Table3
group by convert(date, date)
) T3 on isnull(T1.Date,T2.Date) = T3.Date
group by rollup(coalesce(T1.Date,T2.Date,T3.Date))

Related

Joining Two Tables, getting Aggregate and unique value of one

This may have been answered previously, but I'm having a difficult time describing my issue.
Let's say I have two tables
Table1
User, CalendarID
Joe 1
Joe 2
Joe 3
Sam 4
Bob 1
Jim 2
Jim 3
Table2
CalendarID, CalendarTime
1 2014-08-18 00:00:00.000
2 2015-01-19 00:00:00.000
3 2015-08-24 00:00:00.000
4 2016-01-18 00:00:00.000
What I would like to do is Join the two tables, only getting a single User Name, and Calendar ID based on what is this highest CalendarTime associated with that CalandarID.
So I would like the query to return
User CalendarID
Joe 3
Sam 4
Bob 1
Jim 3
The closest I've managed is
SELECT t1.User, MAX(t2.CalendarTIme) AS CalendarTime
FROM table1 t1
INNER JOIN table2 as t2
ON t1.CalendarID = t2.CalendarID
Group By t1.User
Which gets me the User and CalendarTime that I want, but not the Calendar ID, which is what I really want. Please help.
Closest to your script and pretty straightforward:
SELECT t1.User, t2.*
FROM table1 t1
INNER JOIN table2 as t2
ON t1.CalendarID = t2.CalendarID
WHERE NOT EXISTS
(
SELECT 1 FROM table1 t1_2
INNER JOIN table2 t2_2
ON t2_2.Calendar_ID = t1_2.Calendar_ID
WHERE t1_2.User = t1.User
AND t2_2.CalendarTime > t2.CalendarTime
)
This can be solved for the top N per group:
using top with ties with row_number():
select top 1 with ties
t1.User, t1.CalendarId, t2.CalendarTime
from table1 t1
inner join table2 as t2
on t1.Calendarid = t2.Calendarid
order by row_number() over (partition by t1.User order by t2.CalendarTime desc)
or using common table expression(or a derived table/subquery) with row_number()
;with cte as (
select t1.User, t1.CalendarId, t2.CalendarTime
, rn = row_number() over (partition by t1.User order by t2.CalendarTime desc)
from table1 t1
inner join table2 as t2
on t1.Calendarid = t2.Calendarid
)
select User, CalendarId, CalendarTime
from cte
where rn = 1

Filter out some records on particular periods

I have below tables structures,
Trans Table:
Trans_Id(PK) User_Id(FK) Arroved_Date
________________________________________________
1 101 05-06-2016
2 101 20-06-2016
3 102 06-06-2016
4 103 10-06-2016
5 103 25-06-2016
Table2:
Id(Pk) User_Id(Fk) Start_Date End_Date
__________________________________________________________________
1 101 01-06-2016 15-06-2016
2 103 05-06-2016 20-06-2016
I want to filter out the transaction, if the Approved_Date is not between the users Start_Date and End_Date of table2.
Expected Result:
Trans_Id
________
2
3
5
This query should give you the expected results:
select t1.trans_id from t1
left join t2
on t1.user_id=t2.user_id
where t2.id is null OR t1.Arroved_Date not between t2.Start_Date and t2.End_Date
Try
SELECT Trans_ID
FROM Table1
JOIN Table2 ON Table1.User_Id=Table2.User_Id
where Approved_date Between Start_Date And End_Date
i'm not sure but from you expected output..
SELECT distinct t1.Trans_ID
FROM Table1 t1
LEFT JOIN Table2 t2 on 1=1
where t1.Approved_date Between t2.Start_Date And t2.End_Date
Based on your explanation (not on the expected result) you need to just JOIN the two tables on the FK you pointed out, in order to get the relationship between the rows in the two tables.
Then just apply a WHERE clause to filter the row based on your condition:
select t.trans_id
from trans t
inner join table2 t2 on t.user_id = t2.user_id
where t.approved_date between t2.start_date and t2.end_date
SELECT t.trans_id
FROM Trans tr
LEFT JOIN Table2 t2 ON tr.User_id = t2.User_id
WHERE t2.id IS NULL
OR t.Approved_Date IS NULL
OR t2.Start_Date IS NULL
OR t2.End_Date IS NULL
OR tr.Approved_Date <= t2.Start_Date
OR tr.Approved_Date >= t2.End_Date
The null-checks are only needed if the columns are nullable. The left join can be changed to an inner join if every transaction has a corresponding row in table 2. The answer assumes that there is not more than one row in table 2 for each transaction.
Try this one.
SELECT A.Trans_ID
FROM TEMP A
JOIN TEMP B ON A.User_Id = B.User_Id
WHERE A.Approved_date BETWEEN Start_Date AND End_Date

Using SQL Server how can I query across three separate tables outer joining on a common column between all three of them?

I'm looking to achieve the following output from the given structure. I've included my attempt at this query but it has a fundamental problem. Across millions of records using common dates loses efficiency because it will be querying the breakfasts table (for instance) for dates that don't exist in the breakfasts table.
Desired output:
/*
DESIRED OUTPUT
Date BreakfastAttendees LunchAttendees DinnerAttendees
2016-01-01 10 10 10
2016-02-01 NULL 10 10
2016-03-01 NULL NULL 10
*/
Structure
declare #breakfasts table(Date datetime, Attendees int);
declare #lunches table(Date datetime, Attendees int);
declare #dinners table(Date datetime, Attendees int);
insert into #breakfasts values('01/01/2016',10);
insert into #lunches values('01/01/2016',10);
insert into #lunches values('02/01/2016',10);
insert into #dinners values('01/01/2016',10);
insert into #dinners values('02/01/2016',10);
insert into #dinners values('03/01/2016',10);
Attempt
;With CommonDates_cte as
(
select distinct Date
from #breakfasts
union
select distinct Date
from #lunches
union
select distinct Date
from #dinners
)
select
cte.Date, BreakfastAttendees, LunchAttendees, DinnerAttendees
from
CommonDates_cte cte
cross apply
(select
SUM(Attendees) AS BreakfastAttendees
from #breakfasts b
where b.Date = cte.Date) b
cross apply
(select
SUM(Attendees) AS LunchAttendees
from #lunches l
where l.Date = cte.Date) l
cross apply
(select
SUM(Attendees) AS DinnerAttendees
from #dinners d
where d.Date = cte.Date) d
this assumes date can repeat
if not there are better answers
;With CommonDates_cte as (
select Date
, Attendees as BreakfastAttendees
, 0 as LunchAttendees
, 0 as DinnerAttendees
from #breakfasts
union all
select Date
, 0 as BreakfastAttendees
, Attendees as LunchAttendees
, 0 as DinnerAttendees
from #lunches
union all
select Date
, 0 as BreakfastAttendees
, 0 as LunchAttendees
, Attendees as DinnerAttendees
from #dinners
)
select date, sum(BreakfastAttendees), sum(LunchAttendees), sum(DinnerAttendees)
from CommonDates_cte
group by date
or
;With CommonDates_cteB as (
select Date, sum(Attendees)
from #breakfasts
group by Date )
, CommonDates_cteL as (
select Date, sum(Attendees)
from #lunches
group by Date )
, CommonDates_cteD as (
select Date, sum(Attendees)
from #dinners
group by Date )
SELECT COALESCE(b.[Date], l.[Date], d.[Date]),
b.Attendees AS BreakfastAttendees,
l.Attendees AS LunchAttendees,
d.Attendees AS DinnerfastAttendees
FROM CommonDates_cteB AS b
FULL JOIN CommonDates_cteL AS l ON l.[Date] = b.[Date]
FULL JOIN CommonDates_cteD AS d ON d.[Date] = b.[Date]
if date does not repeat then
SELECT COALESCE(b.[Date], l.[Date], d.[Date]),
b.Attendees AS BreakfastAttendees,
l.Attendees AS LunchAttendees,
d.Attendees AS DinnerfastAttendees
FROM #breakfasts AS b
FULL JOIN #lunches AS l ON l.[Date] = b.[Date]
FULL JOIN #dinners AS d ON d.[Date] = b.[Date]
You can give this query a try:
SELECT COALESCE(b.[Date], l.[Date], d.[Date]),
SUM(b.Attendees) AS BreakfastAttendees,
SUM(l.Attendees) AS LunchAttendees,
SUM(d.Attendees) AS DinnerfastAttendees
FROM #breakfasts AS b
FULL JOIN #lunches AS l ON b.[Date] = l.[Date]
FULL JOIN #dinners AS d ON d.[Date] = l.[Date]
GROUP BY COALESCE(b.[Date], l.[Date], d.[Date])
The query assumes that there is only a single record for any given date for all three tables.

Joining two select statement in sql

I have two select statements. 1st selectreturns data from previous year 2012, while 2nd select displays the current year. How will i join those two to get my desired output.
select a.id, b.item, a.sum(qty) as 'yr1qty', a.yr1amt from table A
left join table B on a.code = b.code
where date between '04/01/2012' and '04/07/2012'
group by a.id, b. item
select a.id, b.item, a.sum(qty) as 'yr2qty', a.yr2amt from table A
left join table B on a.code = b.code
where date between '04/01/2013' and '04/07/2013'
group by a.id, b. item
desired output:
id item yr1qty y1amt yr2qty yr2amt
01 item01 20 2000.00 5 500.00
02 item02 8 400.00
03 item03 10 1250.00
04 item04 3 60.00 2 40.00
05 item05 8 400.00
You should be able to join the two as subqueries using a full outer join
select
coalesce(a.id,b.id),
coalesce(a.item,b.item),
yr1qty,
yr1amt,
yr2qty,
yr2amt
from
(
select a.id, b.item, a.sum(qty) as 'yr1qty', a.yr1amt from table A
left join table B on a.code = b.code
where date between '04/01/2012' and '04/07/2012'
group by a.id, b. item) as a
full outer join
(
select a.id, b.item, a.sum(qty) as 'yr2qty', a.yr2amt from table A
left join table B on a.code = b.code
where date between '04/01/2013' and '04/07/2013'
group by a.id, b. item
) as b on a.id = b.id
Do you need two? Here's the result in one query ...
select a.id, b.item,
a.sum(
CASE WHEN date between '04/01/2012' and '04/07/2012'
THEN qty
ELSE 0
END) AS 'yr1qty', a.yr1amt,
a.sum(
CASE WHEN date between '04/01/2013' and '04/07/2013'
THEN qty
ELSE 0
END) AS 'yr2qty', a.yr2amt
from table A
left join table B on a.code = b.code
group by a.id, b.item
Did you need to use pivot?
select id,item, yr1qty,yr1amt, yr2qty, yr2amt from
(
select a.id, b.item, a.qty, a.amt,
case
when [date] between '2012-01-04' and '2012-07-01' then 'yr1qty'
when [date] between '2013-01-04' and '2013-07-01' then 'yr2qty'
else 'oor'
end as yrqty,
case
when [date] between '2012-01-04' and '2012-07-01' then 'yr1amt'
when [date] between '2013-01-04' and '2013-07-01' then 'yr2amt'
else 'oor'
end as yramt
from A
left join B on a.code = b.code
) x
pivot (
sum(qty) for yrqty in ([yr1qty],[yr2qty])
) qtyTotal
pivot (
sum(amt) for yramt in ([yr1amt],[yr2amt])
) amtTotal

tsql-Joining tables with group by

Have 2 tables TableA
StudentID MeetingID TeacherID Date
001 1002581 1056 10-12-2012
001 1006789 1056 10-13-2012
001 1006754 1058 10-13-1012
Have one more table B
StudentID MeetingID TeacherID Date Value
001 1002581 1056 10-12-201 15
001 1002856 1056 10-20-2012 21
The conditions are max(date) of a particular student teacher meeting from table A matches the max(date) of the same student teacher meeting in table B with the value. I would like to see the resultset as something like
StudentID MeetingID TeacherID Date Value
001 1006789 1056 10-20-2012 21
How can i achieve the above resultset
First, I'm curious why you have the same data in two separate tables instead of linking them via ID. I.e. Meetings -> Values
Per your requirements, this should work. This finds the most recent meeting which is present in both tables.
SELECT B.*
FROM B INNER JOIN A ON B.StudentID = A.StudentID AND B.MeetingID = A.MeetingID AND B.Date = A.Date
WHERE B.Date = (SELECT MAX(Date) FROM A WHERE A.StudentID = B.StudentID AND A.MeetingID = B.MeetingID)
Here's the Fiddle: http://sqlfiddle.com/#!6/d15ca/4
SELECT TOP 1 c.StudentID,c.MeetingID,c.TeacherID,c.tab1_dates,c.VALUE
FROM
(
SELECT a.StudentID,a.MeetingID,a.TeacherID,a.Dates AS tab1_dates,b.Dates AS tab2_dates,b.VALUE,
ROW_NUMBER() OVER (ORDER BY a.Dates,b.Dates) AS RN1
FROM tab2 b
INNER JOIN
(
SELECT StudentID,MeetingID,TeacherID,Dates FROM tab1
) a
ON b.StudentID = a.StudentID
AND b.TeacherID = a.TeacherID
) c
ORDER BY RN1 DESC
--SQL Fiddle - http://www.sqlfiddle.com/#!3/c6cea/1
Sorry, couldn't format well.

Resources