Selecting last date available and one before last - sql

I have a table #sales in which I record sales and profits
The select below gives me the summary of sales and profits for 2 specific dates
The challenge is as follows:
Instead of hard-coding the date, I would need to replace it with:
First date: get the last available date. I though of using max(fecha_valor) but I get an error.
Second date: the one before last available date
so in the example below would be:
First date: '20140714'
Second date: '20140712'
Is it possible to have an additional column with columna_1_p / columna_1 ?
Can anyone help with this?
DECLARE #sales TABLE
(
custom VARCHAR(10) NOT NULL,
fecha_valor DATE NOT NULL,
sales NUMERIC(10, 2) NOT NULL,
profits NUMERIC(10, 2) NOT NULL
);
INSERT INTO #sales(Custom, Fecha_valor, sales, profits)
VALUES ('q', '20140708', 51,21),
('q', '20140712', 3,33),
('q', '20140712', 5,12),
('q', '20140711', 6,43),
('q', '20140712', 2,66),
('q', '20140712', 7,21),
('q', '20140714', 24,76),
('q', '20140714', 24,12),
('x', '20140709', 25,0),
('x', '20140710', 16,0),
('x', '20140711', 66,31),
('x', '20140712', 23,12),
('x', '20140712', 35,11),
('x', '20140714', 57,1),
('c', '20140712', 97,2),
('c', '20140714', 71,3);
SELECT
custom,
CAST(SUM(Case fecha_valor when '2014-07-12' then sales ELSE 0 END) AS numeric(12, 3)) as columna_1,
CAST(SUM(Case fecha_valor when '2014-07-14' then sales ELSE 0 END) AS numeric(12, 3)) as columna_2,
CAST(SUM(Case fecha_valor when '2014-07-12' then profits ELSE 0 END) AS numeric(12, 3)) as columna_1_P,
CAST(SUM(Case fecha_valor when '2014-07-14' then profits ELSE 0 END) AS numeric(12, 3)) as columna_2_P
FROM
#sales
GROUP BY
custom;

You can use following query:
DECLARE #FirstDate DATE,
#SecondDate DATE
SELECT #FirstDate = MAX(fecha_valor) FROM #Sales
SELECT #SecondDate = MAX(fecha_valor) FROM #Sales WHERE fecha_valor<> #FirstDate
SELECT custom,
CAST(SUM(Case fecha_valor when #SecondDate THEN sales ELSE 0 END) AS numeric(12, 3)) as columna_1,
CAST(SUM(Case fecha_valor when #FirstDate THEN sales ELSE 0 END) AS numeric(12, 3)) as columna_2,
CAST(SUM(Case fecha_valor when #SecondDate THEN profits ELSE 0 END) AS numeric(12, 3)) as columna_1_P,
CAST(SUM(Case fecha_valor when #FirstDate THEN profits ELSE 0 END) AS numeric(12, 3)) as columna_2_P
FROM #sales
GROUP BY custom;

Not sure on what exactly you are looking for in your final result but would something along the lines of the below work?
SELECT Custom, Fecha_valor, sales, profits FROM sales ORDER BY Fecha_valor DESC LIMIT 2

Related

How to sum up Loss amount per each claim ignoring date

I have table with Loss amount per each transaction date.
How can I create column ClaimLoss that would sum up Loss amount per each claim?
declare #TempTable1 table (ID int, ClaimNumber varchar(100), date date, Loss money)
insert into #TempTable1
values (1, 'Claim1','2017-01-01', 100),
(2, 'Claim1','2017-03-06',150),
(3, 'Claim1','2017-05-01', 50),
(4, 'Claim2','2018-01-01', 150),
(5, 'Claim2','2018-08-15', 250),
(6, 'Claim2','2018-05-03', 350),
(7, 'Claim3','2018-09-01', 330),
(8, 'Claim4','2019-01-01', 140),
(9, 'Claim4','2019-01-13', 225),
(10, 'Claim5','2019-02-01', 145)
select ID,
ClaimNumber,
Date,
Loss
from #TempTable1
I need something like this:
Is it possible to do in the same select statement?
This seems like a place to use row_number() and case:
select t.*,
(case when row_number() over (partition by ClaimNumber order by date) = 1
then sum(loss) over (partition by ClaimNumber)
else 0
end) as claimloss
from #TempTable1 t;
You can use window function:
select ID, ClaimNumber, Date, Loss,
(case when min(id) over (partition by ClaimNumber) = id
then sum(loss) over (partition by ClaimNumber)
else 0
end) as claimloss
from #TempTable1;

Return back data horizontally

Am kinda lost in here.
I have a table with multiple duplicate values in the same column which i want to return back with S/N and Group as one unique value and then the price of each package in separate column as ('1D' AS DAILY, '1W' AS WEEKLY, AND '1M' AS 'MONTHLY').
am using MS SQL 2012
Thanks in Advance
regards,
Adnan
select [S/N], [group],
sum(case when package = '1D' then price else 0 end) as [daily price],
sum(case when package = '1W' then price else 0 end) as [weekly price],
sum(case when package = '1M' then price else 0 end) as [monthly price]
from rates
group by [S/N], [group]
You could also use the PIVOT operator:
if OBJECT_ID('tempdb..#Rates') is not NULL drop table #Rates
create table #Rates(
S_N int not null,
_group varchar(10) not null,
Package char(2) not null,
price int not null
)
insert into #Rates
values (8, 'D' , '1M', 3700)
,(8, 'I-DC','1M', 1750)
,(8, 'TB', '1M', 7000)
,(12, 'A', '1D', 80)
,(12, 'A', '1W', 480)
,(12, 'A', '1M', 1800)
,(12, 'B', '1D', 90)
,(12, 'B', '1W', 540)
,(12, 'B', '1M', 2100)
select S_N, _group, pvt.[1D] as "DailyPrice1D", pvt.[1W] as "WeeklyPrice1W", pvt.[1M] as "MonthlyPrice1M"
from #Rates
pivot(avg(price) FOR Package in ("1D", "1W", "1M")) pvt
ORDER by S_N
Do you need more explanation or is this code sample enough?
For more information here is the Microsoft documentation: https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017

Select with formula that includes previous value

DECLARE #sales TABLE
(
code VARCHAR(10) NOT NULL,
date1 DATE NOT NULL,
sales NUMERIC(10, 2) NOT NULL,
profits NUMERIC(10, 2) NOT NULL
);
INSERT INTO #sales(Code, Date1, sales, profits)
VALUES ('q', '20140708', 0.51,21),
('q', '20140712', 0.3,33),
('q', '20140710', 0.5,12),
('q', '20140711', 0.6,43),
('q', '20140712', 0.2,66),
('q', '20140713', 0.7,21),
('q', '20140714', 0.24,76),
('q', '20140714', 0.24,12),
('x', '20140709', 0.25,0),
('x', '20140710', 0.16,0),
('x', '20140711', 0.66,31),
('x', '20140712', 0.23,12),
('x', '20140712', 0.35,11),
('x', '20140714', 0.57,1),
('c', '20140712', 0.97,2),
('c', '20140714', 0.71,3);
SELECT code,
CONVERT(VARCHAR, date1, 104) AS SPH_DATE_FORMATO,
Cast(Sum(sales)
OVER (
ORDER BY date1) AS NUMERIC (18, 2)) AS SPH_CLOSE
FROM #sales
WHERE date1 > Dateadd(month, -21, Getdate())
AND code = 'q'
This select gives me the accmulated sales ordered by date for the 'g' code and this is fine.
But now I would need an additional column that calculates:
(1+ previous day sales)*(1+ today sales) -1
also ordered by date for the 'g' code
Can anyone help with this, please?
you can do like this using CTE, just change your select query like this
;with Sales as
(
SELECT code, convert(varchar, date1, 104) AS SPH_DATE_FORMATO, cast(SUM(sales) OVER (ORDER BY date1) as numeric (18,2)) AS SPH_CLOSE,ROW_NUMBER() OVER(ORDER BY Date1 ASC) as rowid
FROM #sales
where date1 >DATEADD(month, -21, GETDATE()) and code='q')
select S1.code,S1.SPH_DATE_FORMATO,S1.SPH_CLOSE
,S2.SPH_close as Sales_Last_Day
from Sales S1 left outer join Sales S2 on S1.rowid -1 = S2.rowid

30/60/90 Day Sumation Query

I have the following query. It pulls invoice and time entries, and calculates the EHR (effective hourly rate) for each client, on a per month basis. What I need to get is:
company ,agreement ,lastMonthEHR,60dayEHR,90dayEHR,6MoEHR,12MoEHR,LifeEHR
CompanyA,AgreementB, 30.45, 27.76, 55.22, 30.75, 30.00, 25.00
EDIT:
I apologize for the format. I'll see if I can format it better. The following query returns monthly invoices, with EHR calculated.
SELECT a.AGR_Name, AGR_Type.AGR_Type_Desc, c.Company_Name, ap.InvoiceDate,ap.Revenue,ap.Hours,ap.EHR
FROM AGR_Header AS a INNER JOIN Company AS c ON a.Company_RecID = c.Company_RecID
LEFT JOIN AGR_Type ON a.AGR_Type_RecID = AGR_Type.AGR_Type_RecID
LEFT JOIN (
SELECT ar.AGR_Header_RecID,ar.Revenue,ac.InvoiceDate,ISNULL (ac.Hours, 0) AS Hours,
CASE
WHEN ac.Hours IS NULL THEN (ar.Revenue)
WHEN ac.Hours <= 1 THEN (ar.Revenue)
ELSE CAST (ar.Revenue / NULLIF (ac.Hours,0) as NUMERIC (9,2))
END AS 'EHR'
FROM (
SELECT ah.AGR_Header_RecID,
DATEADD(month,ai.Month_Nbr-1,dateadd(year,ai.Year_Nbr-2000,'2000-01-01')) as InvoiceDate,
CAST (ai.Monthly_Inv_Amt AS NUMERIC (9, 2)) AS Revenue
FROM
dbo.AGR_Header AS ah INNER JOIN
dbo.AGR_Invoice_Amt AS ai ON ah.AGR_Header_RecID = ai.AGR_Header_RecID
GROUP BY ah.AGR_Header_RecID, ai.Month_Nbr, ai.Year_Nbr) as ar
LEFT JOIN (
SELECT ah.AGR_Header_RecID,SUM(te.Hours_Actual) AS Hours, dateadd(month, datediff(month,0,te.Date_start),0) as InvoiceDate
FROM
dbo.Time_Entry AS te INNER JOIN
dbo.AGR_Header AS ah ON te.Agr_Header_RecID = ah.AGR_Header_RecID
WHERE (te.Agr_Header_RecID IS NOT NULL) AND (te.Agr_Hours IS NOT NULL)
GROUP BY ah.AGR_Header_RecID, dateadd(month, datediff(month,0,te.Date_Start),0)) AS ac ON ar.AGR_Header_RecID = ac.AGR_Header_RecID
AND ar.InvoiceDate = ac.InvoiceDate) AS ap ON ap.AGR_Header_RecID = a.AGR_Header_RecID
ORDER BY Company, Agreement, InvoiceDate
The SQL you posted is pretty complicated, but I think it can be simplified. I think the key is to get the invoice data into a format that is similar to the following:
DECLARE #invoice AS TABLE(
[ID] INT,
[CompanyID] INT,
[InvoiceDate] DATE,
[Hours] DECIMAL(9,2),
[Revenue] DECIMAL(9,2))
From there, the calculations are pretty simple, and they can be done using CASE WHEN statements with minimal subselects (I used one just for clarity, but even that one could be eliminated). Here's a full working example for SQL Server:
--Setup table and dummy data
DECLARE #invoice AS TABLE(
[ID] INT,
[CompanyID] INT,
[InvoiceDate] DATE,
[Hours] DECIMAL(9,2),
[Revenue] DECIMAL(9,2))
INSERT INTO #invoice VALUES(1, 1, '2013-01-01', 5, 100)
INSERT INTO #invoice VALUES(2, 1, '2013-02-01', 6, 100)
INSERT INTO #invoice VALUES(3, 1, '2013-03-01', 7, 100)
INSERT INTO #invoice VALUES(4, 1, '2013-04-01', 8, 100)
INSERT INTO #invoice VALUES(5, 1, '2013-05-01', 9, 100)
INSERT INTO #invoice VALUES(6, 1, '2013-06-01', 10, 100)
INSERT INTO #invoice VALUES(7, 1, '2013-07-01', 11, 100)
INSERT INTO #invoice VALUES(8, 1, '2013-08-01', 12, 100)
INSERT INTO #invoice VALUES(9, 2, '2013-04-01', 5, 100)
INSERT INTO #invoice VALUES(10, 2, '2013-05-01', 6, 100)
INSERT INTO #invoice VALUES(11, 2, '2013-06-01', 7, 100)
INSERT INTO #invoice VALUES(12, 2, '2013-07-01', 8, 100)
--Calculate last month start and end dates
--Hardcoded here for brevity
DECLARE #lastMonthStartDate AS DATETIME
DECLARE #lastMonthEndDate AS DATETIME
SET #lastMonthStartDate = '2013-08-01'
SET #lastMonthEndDate = '2013-09-01'
--Calculate EHRs for different time periods
SELECT
A.CompanyID,
CASE WHEN A.LastMonthHours = 0 THEN 0 ELSE A.LastMonthRevenue / A.LastMonthHours END as [LastMonthEHR],
CASE WHEN A.Last60DaysHours = 0 THEN 0 ELSE A.Last60DaysRevenue / A.Last60DaysHours END as [Last60DaysEHR],
CASE WHEN A.Last90DaysHours = 0 THEN 0 ELSE A.Last90DaysRevenue / A.Last90DaysHours END as [Last90DaysEHR]
FROM (
SELECT
[CompanyID],
SUM(CASE WHEN [InvoiceDate] >= #lastMonthStartDate AND [InvoiceDate] < #lastMonthEndDate THEN [Hours] ELSE 0 END) as [LastMonthHours],
SUM(CASE WHEN [InvoiceDate] >= #lastMonthStartDate AND [InvoiceDate] < #lastMonthEndDate THEN [Revenue] ELSE 0 END) as [LastMonthRevenue],
SUM(CASE WHEN [InvoiceDate] >= DATEADD(d, -60, GETDATE()) THEN [Hours] ELSE 0 END) as [Last60DaysHours],
SUM(CASE WHEN [InvoiceDate] >= DATEADD(d, -60, GETDATE()) THEN [Revenue] ELSE 0 END) as [Last60DaysRevenue],
SUM(CASE WHEN [InvoiceDate] >= DATEADD(d, -90, GETDATE()) THEN [Hours] ELSE 0 END) as [Last90DaysHours],
SUM(CASE WHEN [InvoiceDate] >= DATEADD(d, -90, GETDATE()) THEN [Revenue] ELSE 0 END) as [Last90DaysRevenue]
FROM #invoice
GROUP BY [CompanyID]
) A
I think this approach should work for you. I know I had to simply the problem to illustrate the way I would approach a query like this in my answer, so if you need me to expand on it please let me know.

SQL SUM statements returning different results

Can somebody explain why the two select statement results below are different!
I know the first statement is correct (using CASE) but I can't understand why the second statement is wrong.
CREATE TABLE #sales
(
YearSold int,
Quarter char(2),
Amount money
)
GO
INSERT INTO #sales (YearSold, Quarter, Amount) values (2003, 'Q1', 1)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2003, 'Q2', 2)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2003, 'Q3', 3)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2003, 'Q4', 4)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2004, 'Q1', 5)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2004, 'Q2', 6)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2004, 'Q3', 7)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2004, 'Q4', 8)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2005, 'Q1', 9)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2005, 'Q2', 10)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2005, 'Q3', 0)
INSERT INTO #sales (YearSold, Quarter, Amount) values (2005, 'Q4', 0)
GO
SELECT YearSold,
SUM(CASE Quarter WHEN 'Q1' THEN Amount ELSE 0 END) AS Q1,
SUM(CASE Quarter WHEN 'Q2' THEN Amount ELSE 0 END) AS Q2,
SUM(CASE Quarter WHEN 'Q3' THEN Amount ELSE 0 END) AS Q3,
SUM(CASE Quarter WHEN 'Q4' THEN Amount ELSE 0 END) AS Q4
FROM #sales
GROUP BY YearSold
SELECT t.YearSold, SUM(a.Amount) AS Q1, SUM(b.Amount) AS Q2, SUM(c.Amount) AS Q3, SUM(d.Amount) AS Q4
FROM #sales t
LEFT JOIN #sales a ON t.YearSold = a.YearSold AND a.Quarter='Q1'
LEFT JOIN (select * from #sales where Quarter='Q2') b ON t.YearSold = b.YearSold
LEFT JOIN (select * from #sales where Quarter='Q3') c ON t.YearSold = c.YearSold
LEFT JOIN (select * from #sales where Quarter='Q4') d ON t.YearSold = d.YearSold
GROUP BY t.YearSold
--select * from #sales
DROP TABLE #sales
Note: Using SQL Server 2008 Express
A left join returns every matching row in the right-hand table for each row in the left-hand table.
To see what happens, remove the group by from your second query.
SELECT *
FROM #sales t
LEFT JOIN #sales a ON t.YearSold = a.YearSold AND a.Quarter='Q1'
LEFT JOIN (select * from #sales where Quarter='Q2') b ON t.YearSold = b.YearSold
LEFT JOIN (select * from #sales where Quarter='Q3') c ON t.YearSold = c.YearSold
LEFT JOIN (select * from #sales where Quarter='Q4') d ON t.YearSold = d.YearSold
You'll see there are four rows for each year. That's because from #sales will give you four rows for each year. The end result is that the group by counts everything four times.