How to get Data from April To Present Date in SQL - asp.net

I am working on financial domain. So I want data from April To May.
Suppose Current Month IS June then I only want April to June of this year and it should group by year and month.
And If Suppose Current Month is February then I want details from last April to Jan i.e. April-2013 to Jan-2014
I have got the solution through CTE If i only run CTE Part of the query it is working perfectly fine
This Part of query..
DECLARE #CurrentDate AS datetime = getdate();
DECLARE #FirstDayInCurrentMonth AS datetime = DATEADD(day, 1 - DATEPART(day, #CurrentDate), #CurrentDate);
DECLARE #LastApril AS datetime = DATEADD(month, -(DATEPART(month, #FirstDayInCurrentMonth) + 8) % 12, #FirstDayInCurrentMonth);
WITH Periods AS (
SELECT #LastApril AS [Period]
UNION ALL
SELECT DATEADD(month, 1, [Period])
FROM Periods
WHERE [Period] < #FirstDayInCurrentMonth
)
SELECT
DATENAME(month, [Period]),
DATEPART(year, [Period]),
FROM Periods
But I want sm.is_approved cloumn also work as above query. when I jon other table with above CTE expression. I want proper group by of sm.is_approved column.
I only have the doubt that what will be the condion for joining the other table.
Please give men the proper condition for the below bold part of the query.
DECLARE #CurrentDate AS datetime = getdate();
DECLARE #FirstDayInCurrentMonth AS datetime = DATEADD(day, 1 - DATEPART(day, #CurrentDate), #CurrentDate);
DECLARE #LastApril AS datetime = DATEADD(month, -(DATEPART(month, #FirstDayInCurrentMonth) + 8) % 12, #FirstDayInCurrentMonth);
WITH Periods AS (
SELECT #LastApril AS [Period]
UNION ALL
SELECT DATEADD(month, 1, [Period])
FROM Periods
WHERE [Period] < #FirstDayInCurrentMonth
)
SELECT
DATENAME(month, [Period]),
DATEPART(year, [Period]),
MONTH(sm.is_approved) as [MONTH],
isnull(sum(ISM.selling_price * siim.qty),0) as Price,
isnull(sum(((tm.tax_amount*(ism.selling_price * siim.qty))/100)),0) as Tax,
isnull(sum((ism.selling_price * siim.qty) + (((tm.tax_amount*(ism.selling_price * siim.qty))/100))),0) as TotalPrice
FROM Periods
**LEFT OUTER JOIN RS_Sell_Order_Master as SM on sm.is_approved >= DATEADD(MM, 1, #LastApril)**
left outer join RS_Sells_Invoice_Info_Master as SIIM on sm.sell_order_no = SIIM.sell_order_no
left outer join RS_Inventory_Selling_Master as ISM on ISM.selling_product_id = SIIM.selling_product_id
left outer join RS_Tax_Master as TM on Tm.tax_id = SIIM.tax_id
group by
DATENAME(month, [Period]),
DATEPART(year, [Period]),
MONTH(sm.is_approved)
Can anyone tell me that how to what will be the condition for above query ie bold part of the above query
ie this part I only want this condtion to be true
LEFT OUTER JOIN RS_Sell_Order_Master as SM on sm.is_approved >= DATEADD(MM, 1, #LastApril)

I tried to understand your question, but I'm not sure if I understood :
CTE retrieves all months since last April and you want to display informations linked to RS_Sell_Order_Master (Invoices, Inventory and Taxes...). This should mean, you have to display for all months since last April thoses details.
So maybe you just simply need to make match Periods CTE months and years with RS_Sell_Order_Master months and years.
So you just simply needs to do that :
FROM Periods as P
left outer join RS_Sell_Order_Master as SM
on MONTH(sm.is_approved) = MONTH(P.[Period])
and YEAR(sm.is_approved) = YEAR(P.[Period])
Here in the full code :
DECLARE #CurrentDate AS datetime = getdate();
DECLARE #FirstDayInCurrentMonth AS datetime = DATEADD(day, 1 - DATEPART(day, #CurrentDate), #CurrentDate);
DECLARE #LastApril AS datetime = DATEADD(month, -(DATEPART(month, #FirstDayInCurrentMonth) + 8) % 12, #FirstDayInCurrentMonth);
WITH Periods AS (
SELECT #LastApril AS [Period]
UNION ALL
SELECT DATEADD(month, 1, [Period])
FROM Periods
WHERE [Period] < #FirstDayInCurrentMonth
)
SELECT
DATENAME(month, [Period]),
DATEPART(year, [Period]),
MONTH(sm.is_approved) as [MONTH],
isnull(sum(ISM.selling_price * siim.qty),0) as Price,
isnull(sum(((tm.tax_amount*(ism.selling_price * siim.qty))/100)),0) as Tax,
isnull(sum((ism.selling_price * siim.qty) + (((tm.tax_amount*(ism.selling_price * siim.qty))/100))),0) as TotalPrice
FROM Periods as P
left outer join RS_Sell_Order_Master as SM
on MONTH(sm.is_approved) = MONTH(P.[Period])
and YEAR(sm.is_approved) = YEAR(P.[Period])
left outer join RS_Sells_Invoice_Info_Master as SIIM
on sm.sell_order_no = SIIM.sell_order_no
left outer join RS_Inventory_Selling_Master as ISM
on ISM.selling_product_id = SIIM.selling_product_id
left outer join RS_Tax_Master as TM
on Tm.tax_id = SIIM.tax_id
group by
DATENAME(month, [Period]),
DATEPART(year, [Period]),
MONTH(sm.is_approved)
If i'm wrong correct me, or if you have another issue just leave a comment.

I am not sure, but seeing at the tables I think your joins should be as follows:
FROM Periods
LEFT OUTER JOIN RS_Sell_Order_Master as SM on sm.is_approved >= DATEADD(MM, 1, #LastApril)
INNER join RS_Sells_Invoice_Info_Master as SIIM on sm.sell_order_no = SIIM.sell_order_no
INNER join RS_Inventory_Selling_Master as ISM on ISM.selling_product_id = SIIM.selling_product_id
INNER join RS_Tax_Master as TM on Tm.tax_id = SIIM.tax_id
And Grouping as:
GROUP BY
DATEPART(year, [Period]),
DATENAME(month, [Period]),
MONTH(sm.is_approved)

Try the code below instead of your first three lines, I basically turned the date into a Date without the time which will probably join onto your periods table properly
DECLARE #CurrentDate AS datetime = CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)
DECLARE #FirstDayInCurrentMonth AS datetime = DATEADD(day, 1 - DATEPART(day, #CurrentDate), #CurrentDate)
DECLARE #LastApril AS datetime = DATEADD(month, -(DATEPART(month, #FirstDayInCurrentMonth) + 8) % 12, #FirstDayInCurrentMonth)

first you have to compare between dates e.g. compare Feb-2014 and Apr-2014 if false the you have to subtract one from the year part of April.
You can use functions to compare and substring the date and subtract the date.

First thing, the way you generate dates, you should remove the Hour part using:
DATEADD(hour, 0, DATEDIFF(DAY, 0,#CurrentDate))
Second, try using Inner Join instead of left join.
Still I would suggest you give us better idea of how the data is stored. Possibly add the basic schema and test values in the SQL Fiddle
So I can execute the query and get better idea of what you want.

Related

sqlite3 update column with rollling average

I want to update a column with the rolling average of the product of two other columns, all in the one table.
create table tb (code str, date str, cl float, vo float);
insert into tb values
('BHP', '2020-01-03', 3.25, 1000),
('BHP', '2020-01-04', 3.50, 2000),
('BHP', '2020-01-05', 3.55, 1000),
('CSR', '2020-01-03', 5.55, 1500),
('CSR', '2020-01-04', 5.60, 2000),
('CSR', '2020-01-05', 5.55, 2000),
('DDG', '2020-01-03', 10.20, 4000),
('DDG', '2020-01-04', 10.25, 4500),
('DDG', '2020-01-05', 10.30, 5000);
alter table tb add column dv float;
alter table tb add column avg_dv float;
update tb set dv = (select cl * vo);
select * from tb;
BHP|2020-01-03|3.25|1000.0|3250.0|
BHP|2020-01-04|3.5|2000.0|7000.0|
BHP|2020-01-05|3.55|1000.0|3550.0|
CSR|2020-01-03|5.55|1500.0|8325.0|
CSR|2020-01-04|5.6|2000.0|11200.0|
CSR|2020-01-05|5.55|2000.0|11100.0|
DDG|2020-01-03|10.2|4000.0|40800.0|
DDG|2020-01-04|10.25|4500.0|46125.0|
DDG|2020-01-05|10.3|5000.0|51500.0|
So far, so good. I can select a rolling average -
select code, date, avg(dv)
over (partition by code order by date asc rows 1 preceding)
from tb;
BHP|2020-01-03|3250.0
BHP|2020-01-04|5125.0
BHP|2020-01-05|5275.0
CSR|2020-01-03|8325.0
CSR|2020-01-04|9762.5
CSR|2020-01-05|11150.0
DDG|2020-01-03|40800.0
DDG|2020-01-04|43462.5
DDG|2020-01-05|48812.5
but when I try to put that selection into the avg_vo column of the table I don't get what I was expecting -
update tb set avg_dv =
(select avg(dv)
over (partition by code order by date asc rows 1 preceding)
);
select * from tb;
BHP|2020-01-03|3.25|1000.0|3250.0|3250.0
BHP|2020-01-04|3.5|2000.0|7000.0|7000.0
BHP|2020-01-05|3.55|1000.0|3550.0|3550.0
CSR|2020-01-03|5.55|1500.0|8325.0|8325.0
CSR|2020-01-04|5.6|2000.0|11200.0|11200.0
CSR|2020-01-05|5.55|2000.0|11100.0|11100.0
DDG|2020-01-03|10.2|4000.0|40800.0|40800.0
DDG|2020-01-04|10.25|4500.0|46125.0|46125.0
DDG|2020-01-05|10.3|5000.0|51500.0|51500.0
The avg_dv column has been updated with just the dv values, not the rolling average.
I also tried to adapt the answer here as
update tb
set tb.avg_dv = b.avg_dv
from tb as a inner join
(select code, date, avg(dv)
over (partition by code order by date asc rows 1 preceding)) b
on a.code = b.code and a.date = b.date;
But that just gives me syntax error -
Error: near ".": syntax error
In particular, the reference to "b" in the line
set tb.avg_dv = b.avg_dv
looks like garbage, but I don't know what to replace it with.
Can this be done in a single query?
The code that you tried to adapt in your case uses SQL Server syntax.
If your version of SQLite is 3.33.0+ the correct syntax is:
update tb
set avg_dv = b.avg_dv
from (
select code, date,
avg(dv) over (partition by code order by date asc rows 1 preceding) avg_dv
from tb
) b
where tb.code = b.code and tb.date = b.date;
If you are using a previous version of SQLite that does not support the FROM clause in the UPDATE statement, then you can do it with a CTE:
with cte as (
select code, date,
avg(dv) over (partition by code order by date asc rows 1 preceding) avg_dv
from tb
)
update tb
set avg_dv = (select c.avg_dv from cte c where c.code = tb.code and c.date = tb.date)
Also note that the update statement for the column dv can be written simply:
update tb set dv = cl * vo;
and if your version of SQLite is 3.31.0+, you could create it as generated column so that there is no need for updates:
alter table tb add column dv float generated always as(cl * vo);

Return 0 if the date for a certain day does not have values

I'm doing a query to return the number of count records for a certain date.
The problem is when I use the GroupBy by a certain day, If the date have no records then the date for that day will not be shown in the output.
How can I achieve that?
I'm doing something like:
SELECT COUNT(History.Id)
FROM History
INNER JOIN User ON User.Id = History.UserId
WHERE (#StartDate = #NullDate OR History.CreatedOnDate >= #StartDate)
AND (#EndDate = #NullDate OR History.CreatedOnDate <= #EndDate)
GROUP BY History.CreatedOnDat
Example
01-08, 3 records
02-08, 2 records
04-08, 5 records
I need to have 03-08 with 0 records.
Create a temp table with one day per row:
Declare #StartDate datetime = '2016-08-01'
Declare #EndDate datetime = '2016-08-31'
declare #temp table
(
oneday datetime
);
WHILE #StartDate <= #EndDate
begin
INSERT INTO #temp VALUES (#StartDate);
SET #StartDate = Dateadd(Day,1, #StartDate);
end
select * from #temp
Then, simply join your query with this temp table.

SQL Query Aggregate Error

I have written a query to get a list of users who have not logged anytime within the last 45 days. Here's the query I have so far:
SELECT DISTINCT(EMPLOYEE.EMP_CODE),EMP_TIME_DTL.DATE_ENTERED),EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME FROM EMP_TIME LEFT JOIN
EMP_TIME_DTL ON EMP_TIME.ET_ID = EMP_TIME_DTL.ET_ID LEFT JOIN
EMPLOYEE ON EMP_TIME.EMP_CODE = EMPLOYEE.EMP_CODE
WHERE MAX(EMP_TIME_DTL.DATE_ENTERED) < DATEADD(day, -45, GETDATE())
GROUP BY EMPLOYEE.EMP_CODE, EMP_TIME_DTL.DATE_ENTERED, EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME
The EMP_TIME table contains the hours and the day they worked them. The EMP_TIME_DTL contains the date the employee actually entered the time. That table will have one row for each time entry made. I just want to find: each distinct EMP_CODE for those people who haven't entered time in the last 45 days.
The query I've written will get me those employees who haven't entered time in 45 days, but it also returns all the dates they entered time prior to that 45 day window.
So for example, if the last time John Doe entered time was on MAy 1st, then I want to return that date and his employee id. What I don't want is to return all the time he entered up until May 1st.
I've also tried this:
SELECT DISTINCT(EMPLOYEE.EMP_CODE), (EMP_TIME_DTL.DATE_ENTERED), EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME
FROM EMP_TIME LEFT JOIN
EMP_TIME_DTL ON EMP_TIME.ET_ID = EMP_TIME_DTL.ET_ID LEFT JOIN
EMPLOYEE ON EMP_TIME.EMP_CODE = EMPLOYEE.EMP_CODE
GROUP BY EMPLOYEE.EMP_CODE, EMP_TIME_DTL.DATE_ENTERED, EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME
HAVING MAX(EMP_TIME_DTL.DATE_ENTERED) < DATEADD(day, -45, GETDATE())
Have also tried:
SELECT MAX(EMP_TIME_DTL.ET_ID), MAX(EMP_TIME_DTL.SEQ_NBR), (EMP_TIME.EMP_CODE), EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME, (EMP_TIME_DTL.DATE_ENTERED)
FROM EMP_TIME LEFT JOIN
EMPLOYEE ON EMP_TIME.EMP_CODE = EMPLOYEE.EMP_CODE LEFT JOIN
EMP_TIME_DTL ON EMP_TIME.ET_ID = EMP_TIME_DTL.ET_ID
GROUP BY EMP_TIME.EMP_CODE, EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME, (EMP_TIME_DTL.DATE_ENTERED), EMP_TIME_DTL.ET_ID, EMP_TIME_DTL.SEQ_NBR
HAVING MAX(EMP_TIME_DTL.DATE_ENTERED) < DATEADD(day, -45, GETDATE())
ORDER BY EMP_TIME.EMP_CODE, EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME, EMP_TIME_DTL.ET_ID, EMP_TIME_DTL.SEQ_NBR, (EMP_TIME_DTL.DATE_ENTERED)
Any help or insight would be greatly appreciated!!
I decided to use the following:
WITH EMP_TIME_CTE
(ET_ID, SEQ_NBR, EMP_CODE, LNAME, FNAME, DATE_ENTERED)
AS
(
SELECT MAX(EMP_TIME_DTL.ET_ID), MAX(EMP_TIME_DTL.SEQ_NBR), (EMP_TIME.EMP_CODE), EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME, (EMP_TIME_DTL.DATE_ENTERED)
FROM EMP_TIME LEFT JOIN
EMPLOYEE ON EMP_TIME.EMP_CODE = EMPLOYEE.EMP_CODE LEFT JOIN
EMP_TIME_DTL ON EMP_TIME.ET_ID = EMP_TIME_DTL.ET_ID
WHERE EMPLOYEE.EMP_TERM_DATE IS NULL
GROUP BY EMP_TIME.EMP_CODE, EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME, (EMP_TIME_DTL.DATE_ENTERED), EMP_TIME_DTL.ET_ID, EMP_TIME_DTL.SEQ_NBR
HAVING MAX(EMP_TIME_DTL.DATE_ENTERED) < DATEADD(day, -45, GETDATE())
-- ORDER BY EMP_TIME.EMP_CODE, EMPLOYEE.EMP_LNAME, EMPLOYEE.EMP_FNAME, EMP_TIME_DTL.ET_ID, EMP_TIME_DTL.SEQ_NBR, (EMP_TIME_DTL.DATE_ENTERED)
)
SELECT DISTINCT(EMP_CODE), FNAME + ' ' + LNAME AS FULL_NAME, MAX(DATE_ENTERED) AS DATE_ENTERED
from EMP_TIME_CTE
GROUP BY EMP_CODE, FNAME, LNAME
HAVING MAX(DATE_ENTERED) < DATEADD(day, -45, GETDATE())
ORDER BY EMP_CODE asc

How to get last six month's data in sql

I am developing one chart in that chart I want to show last six month's details separately.
I want to show the details in bar chart.
But I am not getting the any solution.
I am bit weak in sql queries.
Till now I got the data for last month.
But I want the data for last six month.
here's my code.
DECLARE #StartDate DATETIME, #EndDate DATETIME
SET #StartDate = DATEADD(mm, DATEDIFF(mm,0,getdate())-1, 0)
SET #EndDate = DATEADD(mm, 1, #StartDate)
SELECT sum(quantity)
FROM RS_Sell_Order_Master as s
left outer join RS_Sell_Order_Mapping as sm on sm.sell_order_no = s.sell_order_no
left outer join RS_GIN_Master as GIN on gin.product_id = sm.product_id
WHERE del_date BETWEEN #StartDate AND #EndDate
I want o/p of last six month like this suppose I have sell 10 quantity last month & 20 prevous to that month & I didnt sell before that So o/p should be
null
null
null
null
10
20
some thing like this.
This will assign a date exactly 6 months ago - there doesn't seem to be a reason why you would need to go back to the zero datum of SqlServer's DATETIME:
SET #StartDate = DATEADD(mm, -6, CURRENT_TIMESTAMP);
Edit
Assuming that you want month's aligned from the first to the end of each month,
and assuming because you have nulls but still want to show data that we will need to manufacture the missing months (e.g. with a recursive CTE)
DECLARE #StartDate DATETIME;
SET #StartDate = DATEADD(mm, -6, CURRENT_TIMESTAMP);
WITH cte AS
(
SELECT 0 AS TheMonth
UNION ALL
SELECT TheMonth + 1
FROM cte
WHERE TheMonth < 5
)
SELECT sum(quantity)
FROM
cte
LEFT OUTER JOIN RS_Sell_Order_Master as s
ON del_date >= DATEADD(MM, cte.TheMonth, #StartDate) AND del_date < DATEADD(MM, cte.TheMonth + 1, #StartDate)
-- Other Joins here
GROUP BY cte.TheMonth
ORDER BY cte.TheMonth;
SqlFiddle here
total no of items per month can be calculated like
select sum(items),left(date,6)+'01' from yourTable
group by left(date,6)
assuming your date is in 112 format....and it is of varchar(8) type..

Preventing Max function from using timestamp as part of criteria on a date column in PL/SQL

If I query:
select max(date_created) date_created
on a datefield in PL/SQL (Oracle 11g), and there are records that were created on the same date but at different times, Max() returns only the latest times on that date. What I would like to do is have the times be ignored and return ALL records that match the max date, regardless of their associated timestamp in that column. What is the best practice for doing this?
Edit: what I'm looking to do is return all records for the most recent date that matches my criteria, regardless of varying timestamps for that day. Below is what I'm doing now and it only returns records from the latest date AND time on that date.
SELECT r."ID",
r."DATE_CREATED"
FROM schema.survey_response r
JOIN
(SELECT S.CUSTOMERID ,
MAX (S.DATE_CREATED) date_created
FROM schema.SURVEY_RESPONSE s
WHERE S.CATEGORY IN ('Yellow', 'Blue','Green')
GROUP BY CUSTOMERID
) recs
ON R.CUSTOMERID = recs.CUSTOMERID
AND R.DATE_CREATED = recs.date_created
WHERE R.CATEGORY IN ('Yellow', 'Blue','Green')
Final Edit: Got it working via the query below.
SELECT r."ID",
r."DATE_CREATED"
FROM schema.survey_response r
JOIN
(SELECT S.CUSTOMERID ,
MAX (trunc(S.DATE_CREATED)) date_created
FROM schema.SURVEY_RESPONSE s
WHERE S.CATEGORY IN ('Yellow', 'Blue','Green')
GROUP BY CUSTOMERID
) recs
ON R.CUSTOMERID = recs.CUSTOMERID
AND trunc(R.DATE_CREATED) = recs.date_created
WHERE R.CATEGORY IN ('Yellow', 'Blue','Green')
In Oracle, you can get the latest date ignoring the time
SELECT max( trunc( date_created ) ) date_created
FROM your_table
You can get all rows that have the latest date ignoring the time in a couple of ways. Using analytic functions (preferrable)
SELECT *
FROM (SELECT a.*,
rank() over (order by trunc(date_created) desc) rnk
FROM your_table a)
WHERE rnk = 1
or the more conventional but less efficient
SELECT *
FROM your_table
WHERE trunc(date_created) = (SELECT max( trunc(date_created) )
FROM your_table)

Resources