I have a table (that is recreated as part of a query) with the following columns:
ID, Period (which is the number of Months, as an Integer), Payment date, Purchased Date.
I want to create a 5th column in the process: New
The calculation for which would be:
If the Payment date is within X Months of the Purchase date (where X is the number of Months) then 1.
I'm sure that this will be case expression - but I'm not sure how to do the calculation part in the case expression.
Do you just want a case expression? Something like this:
select t.*,
(case when purchasedate >= paymentdate and
purchasedate < dateadd(month, X, paymentdate)
then 1 else 0
end)
from t;
Related
I am using SQL and I would like this number '1000' to appear once per month. I have a record set which has the first of every month appearing multiple times. I would like the number '1000' to appear once only and then '0' for the remaining records until the next month appears. I would like the below please- maybe a case type statement/order parition by? I am using SQL Server 2018 ##SQLSERVER. Please see table below of how i would like the data to appear.
Many Thanks :)
Date
Amount
01/01/2022
1000
01/01/2022
0
01/01/2022
0
01/02/2022
1000
01/02/2022
0
01/02/2022
0
01/03/2022
1000
01/03/2022
0
Solution for your problem:
WITH CT1 AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY CONCAT(MONTH([Date]),YEAR([Date])) ORDER BY [Date]) as rn
FROM your_table
)
SELECT [Date],
CASE WHEN rn = 1 THEN 1000 ELSE 0 END AS Amount
FROM CT1;
Working Example: DB<>Fiddle Link
Given just a list of dates you could use row_number and a conditional expression to arbitrarily assign one row of each month a value of 1000
select *,
Iif(Row_Number() over(partition by Month(date) order by (select null)) = 1, 1000, 0) Amount
from t
order by [date], Amount desc;
My Client wants to generate a code for every ticket number that goes into database based on the financial year they are working (April current year to March next year) and number needs to reset to 0 where the financial year changes
Example:
ID
17/18/0000001
17/18/0000002
...
18/19/0000001
18/19/0000002
...
If the financial year is stored in database like starting an ending month and year. How we can check that this is the next year broda! reset the numbers.
I wouldn't attempt to try and maintain such a counter internally. Rather, I would generate at the time of querying. The query below assumes that your table does have a single ordinary auto increment counter ID as well as a year int column for the fiscal year. We can use the following to generate the counter you want:
SELECT
RIGHT(CONVERT(varchar(4), year), 2) + '/' +
RIGHT(CONVERT(varchar(4), year + 1), 2) + '/' +
RIGHT('0000000' +
CAST(ROW_NUMBER() OVER (PARTITION BY year ORDER BY ID) AS VARCHAR), 7)
FROM yourTable;
Demo
Client is always right. Suppose you have a table
create table #trans(
id int identity(1,1),
transDate datetime
--other fields
)
--the table is filled
declare #dStart date='20160401', --start and end dates
#dEnd date='20170331' --of the first financial year
;with fy as ( -- fill following years
select 1 id, #dStart dStart, #dEnd dEnd
union all
select id+1,DATEADD(year,1,dStart),DATEADD(year,1,dEnd)
from fy
where id<5 --"majic" 5 is arbitrary
)
select dStart,dEnd,t.*,
right(cast(year(dstart) as varchar),2)+'/'+right(cast(year(dEnd) as varchar),2)+'/' -- F.Y. label
+ FORMAT( ROW_NUMBER() over(
partition by right(cast(year(dstart) as varchar),2)+'/'+right(cast(year(dEnd) as varchar),2)+'/' --restart numbering each F.Y.
order by t.id),'000000') ticket
from fy
inner join #trans t on cast(t.transDate as date) between fy.dStart and fy.dEnd
And have what the Client wants.
Disclaimer: If some data are deleted then ticket numbering change.
I want to see all units sold like this
select [UnitsSold] from MyTable
But I also want to add another column showing only the UnitsSold from the last 30 days
How can do this:
MyTable.CreatedOn >= DATEADD(MONTH, -1, GETDATE())
but only for one column.
So basically I want to see on the same row all units sold and then units sold the past 30 days
You can use CASE statement inside your aggregate function, something like....
Select SUM([UnitsSold]) TotalSold
, SUM(CASE WHEN CreatedOn >= DATEADD(MONTH, -1, GETDATE())
THEN [UnitsSold] ELSE 0 END) SoldInLastMonth
FROM MyTable
I have a situation where I am summing up several columns from a table and inserting the results into another table. This is being grouped by county and district. One of the columns is also taking the smallest total sales from a retailer in that district. The problem I have is that there may be some that have less than zero total sales. I only want to write the smallest value that is greater than zero to that column.
declare #WeekEnd datetime
set #WeekEnd = (select top(1) date from sales order by date desc)
select date
,county
,district
,sum(prod1)
,sum(prod2)
,sum(prod3)
,sum(prod4)
,sum(prod1+prod2+prod3+prod4) --Total Sales
,Case when min(prod1+prod2+prod3+prod4) > 0 then min(prod1+prod2+prod3+prod4)
--this works well except for when a total is less than zero, then it is null. I want to avoid the null and have it write the smallest value greater than zero.
end
from sales
where date = #WeekEnd
group by date,county,district
order by county, district
If I am reading your question correctly, you need to get the MIN TotalSales with a subquery:
declare #WeekEnd datetime
set #WeekEnd = (select top(1) date from sales order by date desc)
select date
,county
,district
,sum(prod1)
,sum(prod2)
,sum(prod3)
,sum(prod4)
,sum(prod1+prod2+prod3+prod4) --Total Sales
,(SELECT min(prod1+prod2+prod3+prod4)
FROM sales s2
WHERE s1.date=s2.date
AND s1.county=s2.county
AND s1.district=s2.district
AND (prod1+prod2+prod3+prod4)>0
)
from sales s1
where date = #WeekEnd
group by date,county,district
order by county, district
Haven't tried, but I would assume this works:
min(Case when prod1+prod2+prod3+prod4 <= 0
then null else prod1+prod2+prod3+prod4 end)
I am creating a query to give number of days between two days based on year. Actually I have below type of date range
From Date: TO_DATE('01-Jun-2011','dd-MM-yyyy')
To Date: TO_DATE('31-Dec-2013','dd-MM-yyyy')
My Result should be:
Year Number of day
------------------------------
2011 XXX
2012 XXX
2013 XXX
I've tried below query
WITH all_dates AS
(SELECT start_date + LEVEL - 1 AS a_date
FROM
(SELECT TO_DATE ('21/03/2011', 'DD/MM/YYYY') AS start_date ,
TO_DATE ('25/06/2013', 'DD/MM/YYYY') AS end_date
FROM dual
)
CONNECT BY LEVEL <= end_date + 1 - start_date
)
SELECT TO_CHAR ( TRUNC (a_date, 'YEAR') , 'YYYY' ) AS YEAR,
COUNT (*) AS num_days
FROM all_dates
WHERE a_date - TRUNC (a_date, 'IW') < 7
GROUP BY TRUNC (a_date, 'YEAR')
ORDER BY TRUNC (a_date, 'YEAR') ;
I got exact output
Year Number of day
------------------------------
2011 286
2012 366
2013 176
My question is if i use connect by then query execution takes long time as i have millions of records in table and hence i don't want to use connect by clause
connect by clause is creating virtual rows against the particular record.
Any help or suggestion would be greatly appreciated.
From your vague expected results I think you want the number of records between those dates, not the number of days; but it's rather unclear. Since you refer to a table in the question I assume you want something related to the table data, not simply days between two dates which wouldn't depend on a table at all. (I have no idea what the connect by clause reference means though). This should give you that, if it is what you want:
select extract(year from date_field), count(*)
from t42
where date_field >= to_date('01-Jun-2011', 'DD-MON-YYYY')
and date_field < to_date('31-Dec-2013') + interval '1' day
group by extract(year from date_field)
order by extract(year from date_field);
The where clause is as you'd expect between two dates; I've assumed there might be times in your date field (i.e. not all at midnight) and that you want to count all records on the last date in your range. Then it's grouping and counting based on the year for each record.
SQL Fiddle.
If you want the number of days that have records within the range, then you can just vary the count slightly:
select extract(year from date_field), count(distinct trunc(date_field))
...
SQL Fiddle.
you can use the below function to reduce the number of virtual rows by considering only the years in between.You can check the SQLFIDDLE to check the performance.
First consider only the number of days between start date and the year end of that year or
End date if it is in same year
Then consider the years in between from next year of start date to the year before the end date year
Finally consider the number of days from start of end date year to end date
Hence instead of iterating for all the days between start date and end date we need to iterate only the years
WITH all_dates AS
(SELECT (TO_CHAR(START_DATE,'yyyy') + LEVEL - 1) YEARS_BETWEEN,start_date,end_date
FROM
(SELECT TO_DATE ('21/03/2011', 'DD/MM/YYYY') AS start_date ,
TO_DATE ('25/06/2013', 'DD/MM/YYYY') AS end_date
FROM dual
)
CONNECT BY LEVEL <= (TO_CHAR(end_date,'yyyy')) - (TO_CHAR(start_date,'yyyy')-1)
)
SELECT DECODE(TO_CHAR(END_DATE,'yyyy'),YEARS_BETWEEN,END_DATE
,to_date('31-12-'||years_between,'dd-mm-yyyy'))
- DECODE(TO_CHAR(START_DATE,'yyyy'),YEARS_BETWEEN,START_DATE
,to_date('01-01-'||years_between,'dd-mm-yyyy'))+1,years_between
FROM ALL_DATES;
In Oracle you can perform Addition and Substraction to dates like this...
SELECT
TO_DATE('31-Dec-2013','dd-MM-yyyy') - TO_DATE('01-Jun-2011','dd-MM-yyyy')
DAYS FROM DUAL;
it will return day difference between two dates....
select to_date(2011, 'yyyy'), to_date(2012, 'yyyy'), to_date(2013, 'yyyy')
from dual;
TO_DATE(2011,'Y TO_DATE(2012,'Y TO_DATE(2013,'Y
--------------- --------------- ---------------
01-MAY-11 01-MAY-12 01-MAY-13
select to_char(date_field,'yyyy'), count(*)
from your_table
where date_field between to_date('01-Jun-2011', 'DD-MON-YYYY')
and to_date('31-Dec-2013 23:59:59', 'DD-MON-YYYY hh24:mi:ss')
group by to_char(date_field,'yyyy')
order by to_char(date_field,'yyyy');