Join two 2 tables to get sum of each year - SQL Server - sql

I have 2 tables below. Common column is ObjectId.
Table 1:
Year ObjectId G_Amount
===== ======== ========-
2010 1234 5.00
2010 1234 5.00
2010 5678 10.00
2010 5678 20.00
2010 5678 50.00
2012 9101 0.00
2012 1122 70.00
2012 1122 100.00
Table 2:
ObjectId I_Amount
========= ===========-
1234 10.00
1234 30.00
5678 15.00
5678 20.00
9101 25.00
9101 35.00
1122 10.00
1122 0.00
I want to join above 2 table such that the resultset becomes like below. G_Amount (total of g_amount for each year from Table 1) & I_Amount (total of i_amount for each year from Table 2) should be displayed year wise.
Result set:
Year G_Amount I_Amount
===== ======== ========-
2010 90.00 75.00
2012 170.00 70.00
Can anyone please help?

Your datamodel allows for an object ID to appear in multiple years. The related table2 entries would thus be multiplied, i.e. added to every of these years. If you don't want this, then you need a separate table with one record per object.
As is you'd aggregate the first table by year and object ID and the second by object ID only. Then join and aggregate again to get years.
select
t1.year,
sum(t1.totalg) as total_g_amount,
coalesce(sum(t2.totali), 0) as total_i_amount
from
(
select Year, ObjectId, sum(G_Amount) as totalg
from table1
group by Year, ObjectId
) t1
left join
(
select ObjectId, sum(i_Amount) as totali
from table2
group by ObjectId
) t2 on t2.ObjectId = t1.ObjectId
group by t1.year
order by t1.year;

Something like this will work for your dataset. I've included a LEFT JOIN for any values in Table1 that aren't in Table2:
SELECT
T1.[Year]
, SUM(T1.G_Amount_Total) G_Amount
, ISNULL(SUM(T2.I_Amount_Total), 0) I_Amount
FROM
(
SELECT
[Year]
, ObjectId
, SUM(G_Amount) G_Amount_Total
FROM Table1
GROUP BY
[Year]
, ObjectId
) T1
LEFT JOIN
(
SELECT
ObjectId
, SUM(I_Amount) I_Amount_Total
FROM Table2
GROUP BY ObjectId
) T2
ON T1.ObjectId = T2.ObjectId
GROUP BY T1.[Year]
I do see some potential problems with your data structure, e.g, there is no Year reference in Table2, however, if your data is under control, it should all work out.

Try this , anyway i am new to T-SQL so it can be wrong .
Select DISTINCT T1.Year
SUM (T1.G_Amount) as G_Amount,
SUM (T2.I_Amount) AS I_Amount
from table1 T1 join Table2 T2 on T1.ObjectID = T2.ObjectID

Related

SQL query over several tables

I am trying to write a query with SQL but I don't know how to implement it.
I have given 4 tables with company_ID, reporting year, type_ID and turnover of the company. The values of each company are queried every year, but it is possible that the company does not have a turnover every year or it is also possible that there is no turnover for a company for the whole time. And and it is valid that T1.CompanyID = T2/T3/T4.CompanyID
So now I want to query when is the latest year, as max(ReportingYear), where a turnover is specified and use this reporting year, turnover and CompanyType. If a company had no sales at all over time, the most recent ReportingYear and the associated CompanyType.
I would need these values in the final query:
T1.Company_ext,
T2.taxID,
T3.ReportingYear,
T3.CompanyType,
T4.Turnover,
T4.ReportingYear
With this query I got the companies that ever had any turnover at all.
SELECT
T2.taxID, max(T4.ReportingYear) AS Max_Report
FROM T1
LEFT JOIN T2 ON T1.CompanyID = T2.CompanyIDc.Id
LEFT JOIN T3 ON T1.CompanyID = T3.CompanyIDc.Id
LEFT JOIN T4 ON T1.CompanyID = T4.CompanyIDc.Id AND T4.ReportingYear = T3.ReportingYear
WHERE T4.Turnover IS NOT NULL
GROUP BY T2.taxID
My thought now was that the total quantity - quantity of the above query, must be the ones that had no turnover, however this query runs way too long. Does anyone know a faster way to get the result I want?
The tables look as follows: (In T4 the values I want are marked)
T1:
CompanyID
CompanyId_ext
123
5
124
6
125
7
T2:
CompanyID
taxID
123
1852
124
1935
125
1354
T3:
CompanyID
AttributeID
ReportingYear
CompanyType
123
857269
2022
Public
123
857269
2021
Not Public
124
857270
2022
Not Public
124
857270
2021
Public
125
857271
2022
Not Public
125
857271
2021
Not Public
T4:
CompanyID
Turnover
ReportingYear
123
1000
2022
123
NULL
2021
124
NULL
2022
124
500
2021
125
NULL
2022
125
NULL
2021
If you want to get the CompanyID, the CompanyType and the highest ReportingYear with a Turnover (meaning Turnover != NULL), then this is how you could implement it:
SELECT T4.CompanyID, MAX(T4.ReportingYear), T3.CompanyType
FROM T4
JOIN T3 ON T4.CompanyID = T3.CompanyID
WHERE T4.Turnover != NULL

Access query to return records not found between date range

I have the following sample data
Table1
REF_NO SUPP_START_DATE SUPP_END_DATE
123 01/01/2018 31/12/2018
456 01/01/2017 31/12/2017
789 01/01/2016 31/12/2016
Table2
REF_NO CHG_START_DATE CHG_END_DATE
123 01/03/2018 31/03/2018
123 01/04/2018 30/04/2018
456 01/02/2018 28/02/2018
456 01/01/2017 31/01/2017
789 01/07/2016 31/07/2016
I'd like to know if it is possible to in Access SQL to return all charges (table2) that do not fall between the start and end dates of table1. So, with the sample data above, the following would be returned :-
Results
REF_NO CHG_START_DATE CHG_END_DATE
456 01/02/2018 28/02/2018
I know how to join the 2 tables by using
SELECT table1.ref_no, table2.CHG_START_DATE, table2.CHG_END_DATE
FROM table1
LEFT JOIN table2 ON table1.ref_no = table2.ref_no
but I'm not sure how to cater for the date mismatches
If it is sufficient to just look at the start and end dates:
select t2.*
from table2 t2
where not exists (select 1
from table1 as t1
where t1.refno = t2.refno and
t2.CHG_START_DATE between UPP_START_DATE and SUPP_END_DATE
) or
not exists (select 1
from table1 as t1
where t1.refno = t2.refno and
t2.CHG_END_DATE between UPP_START_DATE and SUPP_END_DATE
) ;
Here's an alternative approach using joins instead of correlated subqueries:
select t2.* from table1 t1 inner join table2 t2 on t1.ref_no = t2.ref_no
where not
(
(t2.chg_start_date between t1.supp_start_date and t1.supp_end_date) and
(t2.chg_end_date between t1.supp_start_date and t1.supp_end_date)
)

Tracing original Value through Iteration SQL

Suppose there is a data collection system that, whenever a record is altered, it is then saved as a new record with a prefix (say M-[most recent number in que and is unique]).
Suppose I am given the following data set:
Customer | Original_Val
1 1020
2 1011
3 1001
I need to find the most recent value for each customer given the following table:
Customer | Most_Recent_Val | Pretained_To_Val | date
1 M-2000 M-1050 20170225
1 M-1050 M-1035 20170205
1 M-1035 1020 20170131
1 1020 NULL 20170101
2 M-1031 1011 20170105
2 1011 NULL 20161231
3 1001 NULL 20150101
My desired output would be:
Customer | Original_Val | Most_Recent_Val | date
1 1020 M-2000 20170225
2 1011 M-1031 20170105
3 1001 1001 20150101
For customer 1, there are 4 levels i.e (M-2000 <- M-1050 <- M-1035 <- 1020) Note that there would be no more than 10 levels of depth for each customer.
Much Appreciated! Thanks in advance.
Find the min and max of each customer and then join it together. Something like this:
Select
[min].Customer
,[min].Most_Recent_Val as Original_Val
,[max].Most_Recent_Val as Most_Recent_Val
,[max].date
From
(
Select
Customer
,Most_Recent_Val
,date
From
table t1
inner join (
Select
Customer
,MIN(date) as MIN_Date
From
table
Group By
Customer
) t2 ON t2.Customer = t1.Customer
and t2.MIN_Date = t1.Date
) [min]
inner join (
Select
Customer
,Most_Recent_Val
,date
From
table t1
inner join (
Select
Customer
,MAX(date) as MAX_Date
From
table
Group By
Customer
) t2 ON t2.Customer = t1.Customer
and t2.MAX_Date = t1.Date
) [max] ON [max].Customer = [min].Customer

cross reference nearest date data

I have three table ElecUser, ElecUsage, ElecEmissionFactor
ElecUser:
UserID UserName
1 Main Building
2 Staff Quarter
ElecUsage:
UserID Time Amount
1 1/7/2010 23230
1 8/10/2011 34340
1 8/1/2011 34300
1 2/3/2012 43430
1 4/2/2013 43560
1 3/2/2014 44540
2 3/6/2014 44000
ElecEmissionFactor:
Time CO2Emission
1/1/2010 0.5
1/1/2011 0.55
1/1/2012 0.56
1/1/2013 0.57
And intended outcome:
UserName Time CO2
1 2010 11615
1 2011 37752 (34340*0.55 + 34300*0.55)
1 2012 24320.8
1 2013 24829.2
1 2014 25387.8
2 2014 25080
The logic is ElecUsage.Amount * ElecEmissionFactor.
If same user and same year, add them up for the record of that year.
My query is:
SELECT ElecUser.UserName, Year([ElecUsage].[Time]), SUM((ElecEmissionFactor.CO2Emission*ElecUsage.Amount)) As CO2
FROM ElecEmissionFactor, ElecUser INNER JOIN ElecUsage ON ElecUser.UserID = ElecUsage.UserID
WHERE (((Year([ElecUsage].[Time]))>=Year([ElecEmissionFactor].[Time])))
GROUP BY ElecUser.UserName, Year([ElecUsage].[Time])
HAVING Year([ElecUsage].[Time]) = Max(Year(ElecEmissionFactor.Time));
However, this only shows the year with emission factor.
The challenge is to reference the year without emission factor to the latest year with emission factor.
Sub-query may be one of the solutions but i fail to do so.
I got stuck for a while. Hope to see your reply.
Thanks
Try something like this..
-- not tested
select T1.id, year(T1.time) as Time, sum(T1.amount*T2.co2emission) as CO2
from ElecUsage T1
left outer join ElecEmissionFactor T2 on (year(T1.time) = year(T2.time))
Group by year(T1.time), T1.id
use sub query to get the corresponding factor in this way
select T1.id,
year(T1.time) as Time,
sum(T1.amount*
(
select top 1 CO2Emission from ElecEmissionFactor T2
where year(T2.time) <= year(T1.time) order by T2.time desc
)
) as CO2
from ElecUsage T1
Group by year(T1.time), T1.id

How to Retrieve Maximum Value of Each Group? - SQL

There is a table tbl_products that contains data as shown below:
Id Name
----------
1 P1
2 P2
3 P3
4 P4
5 P5
6 P6
And another table tbl_inputs that contains data as shown below:
Id Product_Id Price Register_Date
----------------------------------------
1 1 10 2010-01-01
2 1 20 2010-10-11
3 1 30 2011-01-01
4 2 100 2010-01-01
5 2 200 2009-01-01
6 3 500 2011-01-01
7 3 270 2010-10-15
8 4 80 2010-01-01
9 4 50 2010-02-02
10 4 92 2011-01-01
I want to select all products(id, name, price, register_date) with maximum date in each group.
For Example:
Id Name Price Register_Date
----------------------------------------
3 P1 30 2011-01-01
4 P2 100 2010-01-01
6 P3 500 2011-01-01
10 P4 92 2011-01-01
select
id
,name
,code
,price
from tbl_products tp
cross apply (
select top 1 price
from tbl_inputs ti
where ti.product_id = tp.id
order by register_date desc
) tii
Although is not the optimum way you can do it like:
;with gb as (
select
distinct
product_id
,max(register_date) As max_register_date
from tbl_inputs
group by product_id
)
select
id
,product_id
,price
,register_date
from tbl_inputs ti
join gb
on ti.product_id=gb.product_id
and ti.register_date = gb.max_register_date
But as I said earlier .. this is not the way to go in this case.
;with cte as
(
select t1.id, t1.name, t1.code, t2.price, t2.register_date,
row_number() over (partition by product_id order by register_date desc) rn
from tbl_products t1
join tbl_inputs t2
on t1.id = t2.product_id
)
select id, name, code, price, register_date
from cte
where rn = 1
Something like this..
select id, product_id, price, max(register_date)
from tbl_inputs
group by id, product_id, price
you can use the max function and the group by clause. if you only need results from the table tbl_inputs you even don't need a join
select product_id, max(register_date), price
from tbl_inputs
group by product_id, price
if you need field from the tbl_prducts you have to use a join.
select p.name, p. code, i.id, i.price, max(i.register_date)
from tbl_products p join tbl_inputs i on p.id=i.product_id
grooup by p.name, p. code, i.id, i.price
Try this:
SELECT id, product_id, price, register_date
FROM tbl_inputs T1 INNER JOIN
(
SELECT product_id, MAX(register_date) As Max_register_date
FROM tbl_inputs
GROUP BY product_id
) T2 ON(T1.product_id= T2.product_id AND T1.register_date= T2.Max_register_date)
This is, of course, assuming your dates are unique. if they are not, you need to add the DISTINCT Keyword to the outer SELECT statement.
edit
Sorry, I didn't explain it very well. Your dates can be duplicated, it's not a problem as long as they are unique per product id. if you can have duplicated dates per product id, then you will have more then one row per product in the outcome of the select statement I suggested, and you will have to find a way to reduce it to one row per product.
i.e:
If you have records like that (when the last date for a product appears more then once in your table with different prices)
id | product_Id | price | register_date
--------------------------------------------
1 | 1 | 10.00 | 01/01/2000
2 | 1 | 20.00 | 01/01/2000
it will result in having both of these records as outcome.
However, if the register_date is unique per product id, then you will get only one result for each product id.