Aggregation in SQL Server 2014 - sql

I have a data something like this:
declare #table table
(
CUSTNO varchar(35),
RELATIONNO int,
Sales numeric(5,2),
RelationDate dateTIME
)
insert into #table
select 'B1024818', 120, 189.26, '2013-10-27' union all
select 'B1024818', 120, 131.76, '2016-10-28' union all
select 'C0002227', 124, 877.16, '2012-08-26' union all
select 'C0002227', 124, 802.65, '2015-06-15'
I am trying to get a result like
CUSTNO RELATIONNO Sales Till Last Relation Year
----------------------------------------------------------
B1024818 120 321.02 2016
C0002227 124 1679.81 2015
Here sales is added for each customer from 1st Relation date to Last Relation date
In a Till Last Relation Year COLUMN it contain highest year for each customer
I am not sure whether it is possible in SQL.
Please share your suggestions.
Thanks

You could use:
SELECT CUSTNO, RELATIONNO, SUM(Sales) AS Sales, MAX(YEAR(RelationDate))
FROM #table
GROUP BY CUSTNO, RELATIONNO;
Rextester Demo

SELECT custno, RELATIONNO, sum(Sales), MAX(year(RelationDate ))
FROM #table
GROUP BY custno, RELATIONNO

you can use below query -
select CUSTNO ,RELATIONNO ,SUM(Sales) as Sales , max(Year(RelationDate )) [Till Last Relation Year]
from #table
group by CUSTNO ,RELATIONNO

Related

SQL how to sum two rows from the same colum

The picture shows the table
and my question calculate and show lily total fees ( teacher + assistant)
year 2014 - teacher id (123), assistant id (142)
year 2015 - teacher id (523), assistant id (124)
Have you tried a group by?
SELECT
year,
SUM(charge) charge
FROM
your_table
GROUP BY
year
ORDER BY
year;
The structure of the table is not really good, for example the year data is missing.
But you can run the following SQL statement which uses union all:
select '2014' as year,
sum(charge)
from your_table
where id in (123, 142)
union all
select '2015' as year,
sum(charge)
from your_table
where id in (523, 124);

Calculate profit of successive years by adding profit of previous year

Sample data and expected result is provided in the image:
We need to add the profit of previous year with the successive year and display the data in the format given in he image (sample data is also provided in the image).
Please help me with the SQL query to solve this problem.
You can also write this using the window function.
SELECT
Year,
SUM(Profit) OVER(ORDER BY Year) AS Total_Profit
FROM your_table
ORDER BY Year
This is probably the world's simplest recursive CTE which you could have googled.
But here it is:
declare #years table(y int, p int)
insert #years values (2015,1000),(2016,2000),(2017,500),(2018,1000)
; with cumulative as
(
select top 1 * from #years order by y
union all
select y.y, y.p+c.p
from #years y
join cumulative c on y.y=c.y+1
)
select * from cumulative
Result:
y p
2015 1000
2016 3000
2017 3500
2018 4500
Use Sum over partition :
WITH V1 AS (
SELECT 2015 AS YEAR, 1000 AS PROFIT FROM DUAL
UNION ALL SELECT 2016 AS YEAR, 2000 AS PROFIT FROM DUAL
UNION ALL SELECT 2017 AS YEAR, 500 AS PROFIT FROM DUAL
UNION ALL SELECT 2018 AS YEAR, 1000 AS PROFIT FROM DUAL
)
SELECT
V1.YEAR
, PROFIT --- You can comment it if not needed
, SUM(PROFIT) OVER (PARTITION BY 1 ORDER BY YEAR RANGE UNBOUNDED PRECEDING) AS PROFIT_CUM
FROM V1;

Set based query to replace loop to populate all month end dates from given date for all records

I have a table that stores patient lab test results. There can be results from multiple tests like Albumin, Potassium, Phosphorus etc. First reading for each patient from each of these categories is stored in a table called #MetricFirstGroupReading.
CREATE TABLE #MetricFirstGroupReading (Patient_Key INT, Metric_Group VARCHAR(100),
Observation_Date DATE)
ALTER TABLE #MetricFirstGroupReading
ADD CONSTRAINT UQ_MetricFirst UNIQUE (Patient_Key, Metric_Group);
INSERT INTO #MetricFirstGroupReading
SELECT 1, 'Albumin', '2018-11-15' UNION
SELECT 1, 'Potassium', '2018-12-10' UNION
SELECT 2, 'Albumin', '2018-10-20' UNION
SELECT 2, 'Potassium', '2018-11-25'
Now, I need to populate all month end dates upto current month into a new table, for each record from the #MetricFirstGroupReading table. Following is the expected result when the query run on December 2018.
I know how to do it using WHILE loops. How to do this without loops, using set based SQL queries, in SQL Server 2016?
Following worked. This is an expansion of the idea present in tsql: How to retrieve the last date of each month between given date range
Query
CREATE TABLE #AllMonthEnds (MonthEndDate DATE)
DECLARE #Start datetime
DECLARE #End datetime
SELECT #Start = '2000-01-01'
SELECT #End = DATEADD(MONTH,1,GETDATE())
;With CTE as
(
SELECT #Start as Date,Case When DatePart(mm,#Start)<>DatePart(mm,#Start+1) then 1 else 0 end as [Last]
UNION ALL
SELECT Date+1,Case When DatePart(mm,Date+1)<>DatePart(mm,Date+2) then 1 else 0 end from CTE
WHERE Date<#End
)
INSERT INTO #AllMonthEnds
SELECT [Date]
FROM CTE
WHERE [Last]=1
OPTION ( MAXRECURSION 0 )
SELECT T.Patient_Key, T.Metric_Group, T.Observation_Date AS First_Observation_Date,
DATEDIFF(MONTh,Observation_Date, MonthEndDate) AS MonthDiff,
A.MonthEndDate AS IterationDate
FROM #AllMonthEnds A
INNER JOIN
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY Patient_Key, Metric_Group ORDER BY Observation_Date) AS RowVal
FROM #MetricFirstGroupReading M
)T
ON A.MonthEndDate >= T.Observation_Date
WHERE RowVal = 1
ORDER BY Patient_Key, Metric_Group, T.Observation_Date, A.MonthEndDate
How about:
select MetricFirstGroupReading.*, datediff(month, MetricFirstGroupReading.Observation_Date, months.monthendval) monthdiff, months.*
into allmonths
from
(
SELECT 1 patientid, 'Albumin' test, '2018-11-15' Observation_Date UNION
SELECT 1 patientid, 'Potassium' test, '2018-12-10' Observation_Date UNION
SELECT 2 patientid, 'Albumin' test, '2018-10-20' Observation_Date UNION
SELECT 2 patientid, 'Potassium' test, '2018-11-25' Observation_Date) MetricFirstGroupReading
join
(
select '2018-10-31' monthendval union
select '2018-11-30' monthendval union
select '2018-12-31' monthendval
) months on MetricFirstGroupReading.Observation_Date< months.monthendval
Replace the first select union with your table, and add or remove month ends from the second inner select.
Consider building a temp table of all 12 month end dates, then join to main table by date range. Use DateDiff for month difference:
CREATE TABLE #MonthEndDates (Month_End_Value DATE)
INSERT INTO #MonthEndDates
VALUES ('2018-01-31'),
('2018-02-28'),
('2018-03-31'),
('2018-04-30'),
('2018-05-31'),
('2018-04-30'),
('2018-06-30'),
('2018-07-31'),
('2018-08-31'),
('2018-09-30'),
('2018-10-31'),
('2018-11-30'),
('2018-12-31')
SELECT m.Patient_Key, m.Metric_Group, m.Observation_Date,
DateDiff(month, m.Observation_Date, d.Month_End_Value) AS Month_Diff,
d.Month_End_Value
FROM #MetricFirstGroupReading m
INNER JOIN #MonthEndDates d
ON m.Observation_Date < d.Month_End_Value
GO
Rextester Demo

How to find MAX of COUNT Result for Relation

I have Table which consist of PatientId which is Int and Date which is Date Data Type.
It does look like following
patientId Date
101 01/01/2001
102 01/02/2001
103 01/03/2002
104 01/03/2004
105 01/03/2004
106 01/04/2004
And My Desired Result would give me
Count Year
3 2004
since it has the most patients, also it we have two year that has the same number of patients then we should have both year displayed with Number of patients that they had.
Thank you.
Use YEAR function to extract year from your date column. Use extracted year in group by to get the count of Year
select TOP 1 year([Date]),count(1) as [Count]
from Yourtable
Group by year([Date])
Order by [Count] desc
Another way would be using DATEPART
select TOP 1 Datepart(year,[Date]),count(1) as [Count]
from Yourtable
Group by Datepart(year,[Date])
Order by [Count] desc
The DATEPART function is your friend in this case. However, to get all of the rows in case of a tie, a simple TOP will not work. In this case, a different coding method is needed.
You could use a RANK() command, but that is more complex than this calls for. Instead, use a Common Table Expression (CTE).
Here, I set up a table for testing. Since I need two years with the same count of rows, I extended your sample into 2005
CREATE TABLE MyTable (
custID INT,
[Date] DATE
)
TRUNCATE TABLE MyTable;
INSERT INTO MyTable
VALUES
(101, '01/01/2001'),
(102, '01/02/2001'),
(103, '01/03/2002'),
(104, '01/03/2004'),
(105, '01/03/2004'),
(106, '01/04/2004'),
(107, '02/01/2005'),
(108, '02/02/2005'),
(109, '10/10/2005');
This is the CTE I created, which summarizes the data into its year counts, and the queries against the CTE.
WITH MyData AS (
SELECT
DATEPART(year, [Date]) AS [Year],
COUNT(*) AS ct
FROM MyTable
GROUP BY Datepart(year, [Date])
)
-- Now we issue the SELECT statement against the CTE itself
SELECT *
FROM MyData
WHERE ct = (SELECT MAX(ct) FROM MyData)
And here is the output:
Year ct
2004 3
2005 3

How to find the missing rows?

I have a table as shown in the image.
The column MONTH_NO should be having months from 1 to 12 for every year. For some years, we missed to load data for some months. I need a query which will fetch the years which doesn't have all the 12 months along with the missing month number.
Please help.
For example -
with mth
as (select level as month_no
from dual
connect by level <= 12),
yrs as (select distinct year from rag_month_dim)
select m.year, m.month_no
from (select year, month_no
from yrs, mth) m,
rag_month_dim r
where m.year = r.year(+)
and m.month_no = r.month_no(+)
group by m.year, m.month_no
having max(r.month_no) is null
order by year, month_no
Try it like this:
post this into an empty query window and adapt to your needs.
MyData contains a "full" year 2013, Sept is missing in 2014 and June and Sept are missing in 2015.
DECLARE #OneToTwelve TABLE(Nmbr INT)
INSERT INTO #OneToTwelve VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12);
DECLARE #myData TABLE(yearNo INT, MonthNo INT)
INSERT INTO #myData VALUES
(2013,1),(2013,2),(2013,3),(2013,4),(2013,5),(2013,6),(2013,7),(2013,8),(2013,9),(2013,10),(2013,11),(2013,12)
,(2014,1),(2014,2),(2014,3),(2014,4),(2014,5),(2014,6),(2014,7),(2014,8),(2014,10),(2014,11),(2014,12)
,(2015,1),(2015,2),(2015,3),(2015,4),(2015,5),(2015,7),(2015,8),(2015,10),(2015,11),(2015,12);
WITH AllYears AS
(
SELECT DISTINCT yearNo FROM #myData
)
,AllCombinations AS
(
SELECT *
FROM #OneToTwelve AS months
CROSS JOIN AllYears
)
SELECT *
FROM AllCombinations
LEFT JOIN #myData AS md ON AllCombinations.Nmbr =md.MonthNo AND AllCombinations.yearNo=md.yearNo
WHERE md.MonthNo IS NULL
select distinct year, m.lev
from rag_month_dim a
join
(
select level lev
from dual
connect by level <= 12
) m
on 1=1
minus
select year, month_no
from rag_month_dim
order by 1, 2
select *
from (select count (-1) total, year from rag_month_dim group by year) as table
where total < 12.
you got a year that doesnt have 12 month data and total month record in your data.