Linq query on the same table with difference between rows - sql

I've been trying to develop a linq query that returns results from the same table.
ORDERS
YEAR NumberOfOrders
--------------------------
2009 150
2010 195
2011 180
2012 110
The query must returns the diffrence between the current and the last year (2012 and 2011) like follows :
Result:
YEAR NumberofOrders DIFFERENCE
---------------------------------------
2012 110 -70
Thanks for your help,

found it by myself
var query = (from o1 in context.orders
where o1.year == lastyear
from o2 in context.orders
where o2.year == currentyear
select new
{
difference = o2.numberOfOrders - o1.numberOfOrders,
numberOfOrders = o2.numberOfOrders,
year = o2.year
});
Thanks,

Related

How can I pivot and then calculate data?

Pretty new to SQL here. Thank you so much to anyone reading this.
I have a table
ProductID, Year, Sales
------------------------
Product1 2019 100
Product1 2018 50
With a lot of products, but the two years are always 2019 and 2018.
I need to show the 100 products that had the biggest % increase in sales.
I believe that this requires "pivoting" the data, so that you can calculate the 2019 (as one column) and 2018 (second column) difference in a third column called "% increase."
But I'm totally stuck--Ive never done anything this difficult in SQL before.
Help?
Another solution would be this, which would help you if there are more than one record per product - year:
SELECT
ProductId,
Sales_2018,
Sales_2019,
(Sales_2019 - Sales_2018) / Sales_2018 * 100 AS Percentage_increase
FROM (SELECT
ProductID,
SUM(CASE WHEN Year = 2018 THEN Sales END) AS Sales_2018,
SUM(CASE WHEN Year = 2019 THEN Sales END) AS Sales_2019
FROM TABLE
GROUP BY ProductID)
ORDER BY (Sales_2019 - Sales_2018) / Sales_2018 DESC
You can do this with self-join on almost any SQL engine.
Please find the sample implementation below.
You may need to fix some depending on the dialect that you use.
SELECT
a.ProductId,
(1.0 * b.Sales / a.Sales - 1.0) AS IncreaseRate
FROM
tbl AS a
INNER JOIN
tbl AS b
ON
a.ProductId = b.ProductId
AND a.year = 2018
AND b.year = 2019
ORDER BY
IncreaseRate DESC
LIMIT 100

SELECT Brand and Model for cars which have been rented in December 2000?

There is a table called Car with columns CarID, Brand, Model, ProdYear, Color
and a table Rent with columns RentID, CarID, RentDate, ReturnDate.
How to SELECT Brand and Model for cars which have been rented in December 2000?
RentDate and ReturnDate are stored in DATETIME format (YYYY-MM-DD)
For a simplistic scenario:
SELECT DISTINCT Brand, Model
FROM Car
WHERE (MONTH(RentDate) = 'December' AND YEAR(RentDate)) = 2000 or (MONTH(ReturnDate) = 'December'Year(ReturnDate) = 2000)
If you want to dig further and the following will cover four scenarios:
Rented earlier but returned in the year of Dec 2000
rented in 2000 and returned after Dec 2000
Rented in 2000 and returned also in Dec 2000
SELECT DISTINCT Brand, Model
FROM Car
WHERE RentDate <='2020-12-31' AND ReturnDate >= '2020-12-01
Just learn simple join which might help you.
SELECT c.Brand,C.Model
FROM Car c
INNER JOIN Rent r ON r.CarId = c.carId
where Year(r.returnDate) = 2000
AND MONTH(r.returnDate) = 12
I will give you tips to create your request.
First of all, you have to make a join between your 2 table like shown :
... Car INNER JOIN Rent ON Car.CarID = Rent.CarID
Then you have to add a where clause :
Where RentDate in (SELECT RentID, RentDate From Rent WHERE MONTH = 12 AND YEAR = 2000)
As you see, you can use a double request to get all the RentID and Date.
I hope this will work for you and this help you.

SQL Server 2012 - find duplicate month (string) but different year

Having difficulty getting my head around this one.
I've been asked to create a report showing customers who signed up in the same month in previous year.
Invoice table looks a bit like this: (can't figure out how to create a nicer table)
invoiceid customerid monthinvoice yearinvoice
1 50 July 2016*
2 51 July 2016
3 52 July 2016*
4 53 July 2016
5 54 August 2016
6 50 July 2017*
7 51 August 2017
8 52 July 2017*
9 53 August 2017
10 54 September 2017
The only proper date column used is date the invoice was generated and the date payment received.
The records marked with * are the ones I'm only interested in, I just want to see 2 records returned when I pass a month as a parameter (I'll be asked to show how many customers have renewed in August for example. If the 1st invoice was in July 2016 and next invoice in August 2017 they will be treated as a new customer, not a renewal (must be exactly 12 months))
1) 50
2) 52
Any help much appreciated.
Here is one way. First we get all invoices for this month, current year, then union to the same month of the previous year. Then, we filter on customers who have a record for both using HAVING.
;with cte as(
select *
from yourtable
where
(monthinvoice = #monthinvoice
and yearinvoice = datepart(year,getdate()))
union
select *
from yourtable
where
(monthinvoice = #monthinvoice
and yearinvoice = datepart(year,dateadd(year,-1,getdate()))))
select *
from cte
where customerid in (select customerid from cte group by customerid having count(invoiceid) > 1)
I think this should do the trick for you-
SELECT I1.invoiceid, I1.customerid, I1.monthinvoice, I1.yearinvoice, I2.yearinvoice
FROM Invoice_table I1
INNER JOIN Invoice table I2
ON I1.customerid = I2.customerid
AND I1.monthinvoice = I2.monthinvoice
AND I1.yearinvoice = I2.yearinvoice + 1
something like this
select customerid , monthinvoice from yourtable
where yearinvoice in (2016, 2017) and monthinvoice = 'July'
group by customerid , monthinvoice
having count(*) = 2
Something like the following should give you some ideas as to how to build the report out.
Declare #ReportYear as int = 2017;
--this should show all customers with invioices for these months in both 2017 and 2016
select a.customerid, a.monthinvoice
from
(
--get people with invoice last year
Select distinct customerid, monthinvoice
from Invoices i0
where yearinvoice = #ReportYear - 1
) a
join
(
--get people with invoice this year
Select distinct customerid, monthinvoice
from Invoices i0
where yearinvoice = #ReportYear
) b on a.customerid = b.customerid
and a.monthinvoice = b.monthinvoice
If Im following your question correctly...
SELECT customerid FROM InvTblName T
INNER JOIN (SELECT customerID
FROM InvTblName
HAVING Z.invyear=T.invyear+1) Z
ON T.invmonth=Z.invmonth

How do I get a 0 sum when grouping by more than one field?

I have tried looking and found using left outer joins tends to be the answer, but that usually is for a sum to a date grouping and not 2 levels of groupings. I think the additional grouping is messing me up.
My Table:
dbo._Labour
_id int pk --the id of this labour entry
_date date --the date of this entry (using this to group by year)
_activityid int --what type of activity they are doing
_typeid int --3 possible options (0,1,2) of what type of item they are performing the activity on
_hours numeric(4,0) --how many hours were spent performing that activity.
My ultimate goal is to know for each year the total hours spent working for each of the 3 types (0,1,2). My current code:
select coalesce(SUM(_hours),0) as _hours, YEAR(_date) as _year, l._typeid
from RelayTanks.dbo._Labour l
left outer join (select YEAR(_date) as _y
from RelayTanks.dbo._Labour group by YEAR(_date)) y on y._y = YEAR(l._date)
where _activityid in (3,4,9,11)
group by YEAR(_date), l._typeid
order by year(_date), l._typeid'
which results in:
_typeid _year _hours
0 2015 1174
1 2015 3953
2 2015 851
0 2016 119
1 2016 541
2 2016 65
1 2017 10
What I am looking for is 2017 to show _hours 0 for _typeid 0 and a 0 for _typeid 2. ie:
_typeid _year _hours
0 2015 1174
1 2015 3953
2 2015 851
0 2016 119
1 2016 541
2 2016 65
0 2017 0
1 2017 10
2 2017 0
I have tried many things including 2 outer left joins and I just can't quite figure it out. The current out join I thought would be a good substitute to actually having a dummy year table and only showing years where at least some work has been done.
This is my first question posted here so many apologies if I have neglected to include some info or am missing some community etiquette.
Thanks for your help!
This would get you there, assuming that all of the possible years and types are already represented in your data:
SELECT year(_date), _typeid, _hours = SUM(_hours)
FROM _Labour
GROUP BY year(_date), _typeid
UNION
SELECT year(y._date), t._typeid, 0
FROM _Labour y, _Labour t
WHERE NOT EXISTS (SELECT 1 FROM _Labour WHERE year(_Labour._date) = year(y._date) AND _Labour._typeid = t._typeid)
ORDER BY 1, 2
if you have to do this with just one table then something like this might work.
SELECT s._typeid,
s._y,
coalesce(SUM(lj._hours),0) as _hours
FROM
(
SELECT t._typeid, y._y
FROM (SELECT DISTINCT _typeid FROM RelayTanks.dbo._Labour) t
CROSS JOIN
(SELECT DISTINCT YEAR(_date) _y FROM RelayTanks.dbo._Labour) y
) s
LEFT JOIN RelayTanks.dbo._Labour lj ON lj._typeid = s._typeid AND YEAR(lj._date) = s._y
performance might be terrible.. you might want to consider adding a computed column for the _date.year value

How use the operator IN with a subquery that returns two columns

Hello masters I need your help.
Having the table:
DataCollection
==================
PK Code
smallint RestaurantCode
smallint Year
tinyint Month
money Amount
money AccumulativeMonthsAmount
...
I need the AccumulateAmount for the LastMonth on every Restaurant.
First, I get the last Month per Restaurant for the 'current year'(for this case):
SELECT RestaurantCode, MAX(Month) as Month FROM DataCollection
WHERE (Year >= 2012 AND YEAR <= 2012) GROUP BY RestaurantCode
Now I want to use that as subquery, to get the Last - AccumulativeMonthsAmount :
SELECT AccumulativeMonthsAmount FROM DataCollection
WHERE (RestaurantCode, Month)
IN (SELECT RestaurantCode, MAX(Month) as Month FROM DataCollection
WHERE (Year >= 2012 AND YEAR <= 2012) GROUP BY RestaurantCode)
But the operator IN, don't work, How I should do it?
Sample Data sorted by Year and Month:
RestCode Amount Accumulative Year Month
123 343.3 345453.65 2012 12
123 124.7 345329.00 2012 11
...
122 312.2 764545.00 2012 12
122 123.4 764233.00 2012 11
...
999 500.98 2500.98 2012 6
999 100.59 2000.00 2012 5
...
I wanna to get the Accumulative for the last month of every restaurant:
RestCode Accumulative Month
123 345453.65 12
122 764545.00 12
99 2500.98 6
...
SELECT dc.AccumulativeMonthsAmount
FROM dbo.DataCollection AS dc
INNER JOIN
(
SELECT RestaurantCode, MAX(Month)
FROM dbo.PAL_Entries_Relatives
WHERE [Year] = 2012
GROUP BY RestaurantCode
) AS r(rc, m)
ON dc.RestaurantCode = r.rc
AND dc.[Month] = r.m;
With the changed requirements:
;WITH x AS
(
SELECT RestCode, Accumulative, [Month],
rn = ROW_NUMBER() OVER (PARTITION BY RestCode ORDER BY [Month] DESC)
FROM dbo.DataCollection -- or is it dbo.PAL_Entries_Relatives?
)
SELECT RestCode, Accumulative, [Month]
FROM x
WHERE rn = 1
ORDER BY [Month] DESC, RestCode DESC;
That syntax is not allowed in SQL Server. You can do something similar with EXISTS:
SELECT AccumulativeMonthsAmount
FROM DataCollection dc
WHERE exists (select 1
from PAL_Entries_Relatives er
where (Year >= 2012 AND YEAR <= 2012)
group by RestaurantCode
having er.RestaurantCode = dc.RestaurantCode and
max(er.month) = dc.Month
)
SELECT AccumulativeMonthsAmount
FROM DataCollection
INNER JOIN PAL_Entries_Relatives
ON DataCollection.RestaurantCode = PAL_Entries_Relatives.RestaurantCode
WHERE (Year >= 2012 AND YEAR <= 2012)
GROUP BY DataCollection.RestaurantCode
HAVING AccumulativeMonthsAmount.Month = MAX(PAL_Entries_Relatives.Month)