How to Select dates when i sold nothing? - sql

Assume i have a table of item_sold from 01-01-2020 to 01-01-2023 with columns product_id, product_name, quantity and date.
I want to get all the dates when i sold nothing.
I am using Postgresql, please help me in this problem.
I tried withclaue and many other things but they didn't worked.

You need some kind of calendar table containing all dates which you potentially want to report. Assuming the date range be the entire years of 2020 through 2023 inclusive, we can try the following left anti-join approach:
WITH dates AS (
SELECT ('2020-01-01'::date + s.a) AS dt
FROM generate_series(0, 365*4) AS s(a)
)
SELECT d.dt
FROM dates d
LEFT JOIN yourTable t
ON t.item_sold = d.dt
WHERE t.item_sold IS NULL
ORDER BY d.dt;

Related

How to add a set of dates for each category in a dimension?

I have data that looks like this where there is a monthly count of a particular animal for each month. By default, it aggregates in the month where there is data.
However, I would like to like to have a default set of dates for each animal up to the current month date with 0 if there's no data. Desired Result -
Is there a way to handle with a on sql server and not in Excel?
Much appreciated in advance.
You can generate the months you want using a numbers table or recursive CTE (or calendar table). Then cross join with the animals to generate the rows and use left join to bring in the existing data:
with dates as (
select min(date) as dte
from t
union all
select dateadd(month, 1 dte)
from dates
where dte < getdate()
)
select a.animal, d.dte, coalesce(t.monthly_count, 0) as monthly_count
from dates d cross join
(select distinct animal from t) a left join
data t
on t.date = d.dte and t.animal = a.animal
order by a.animal, d.dte;

SQL query that can create a row for skipped months

I have a table that I join to a calendar table, but I need to populate / create new row for each month between. I.e.
Date GIS CODE Running Total Open
2007-04-30 BEJOORDING, 6566, WESTERN AUSTRALIA 5
2007-09-30 BEJOORDING, 6566, WESTERN AUSTRALIA 6
I need some sort of query that can create end of month date rows between 2007-04-30 and 2007-09-30.
I will then need to fill down the blanks with the most recent fields so I will have a timeline for all end of month values.
I am assuming I will have to use some sort of CTE table but I am not the best at this / understand exactly how they work.
Any help will be greatly appreciated.
This CTE query will give you a table with all end-of-month values between the first and last ones in your table (I've assumed called log). You can then LEFT JOIN that to the table to create rows for all months in the timespan.
WITH CTE AS (
SELECT MIN(Date) AS [Date], MAX(Date) AS Max_Date FROM log
UNION ALL
SELECT EOMONTH(DATEADD(MONTH, 1, [Date])), Max_Date
FROM CTE
WHERE Date < Max_Date
)
SELECT Date
FROM CTE
Demo on SQLFiddle
Can be achieved with a RIGHT JOIN to a subquery against the calendar table using the EOMONTH() function

Return sums even if no data exist in given day

I have a table with amounts only on some days, e.g.:
[DATE] [AMT]
11/1/2017 $123
11/1/2017 $50
11/3/2017 $123
How can I query the data and get:
11/1/2017 $173
11/2/2017 $0
11/3/2017 $123
I tried like:
SELECT Day([Date]) AS [Day], Nz(Sum(AMT),0) AS [Day Total]
FROM mytable
WHERE Month([Date])=11
GROUP BY Day([Date]);
But still it doesn't return 0s for days without data, any ideas?
In Access, you can create a series of dates between the first and the last date, and then create an outer join to your summed data.
Here is how to create the date series:
Create a date table between two dates
You need a table with all the days, so you can fill the holes, lets call it allDays
Get a list of dates between two dates using a function
Then your query is:
SELECT a.[date], COALESCE(SUM([AMT]),0)
FROM allDates a
LEFT JOIN yourTable t
ON a.[date] = t.[date]
GROUP BY a.[date]
There are two simple solutions.
Join to a table with all dates in the month, as in Juan's answer.
Use this query by user RedFilter to generate the dates.
I suggest you try the following query:
SELECT DATE_FORMAT(date, "%b") AS month, SUM(total_price) as total
FROM table
WHERE date <= NOW()
and date >= Date_add(Now(),interval - 12 month)
GROUP BY DATE_FORMAT(date, "%m-%Y"))

Calculating business days in Teradata

I need help in business days calculation.
I've two tables
1) One table ACTUAL_TABLE containing order date and contact date with timestamp datatypes.
2) The second table BUSINESS_DATES has each of the calendar dates listed and has a flag to indicate weekend days.
using these two tables, I need to ensure business days and not calendar days (which is the current logic) is calculated between these two fields.
My thought process was to first get a range of dates by comparing ORDER_DATE with TABLE_DATE field and then do a similar comparison of CONTACT_DATE to TABLE_DATE field. This would get me a range from the BUSINESS_DATES table which I can then use to calculate count of days, sum(Holiday_WKND_Flag) fields making the result look like:
Order# | Count(*) As DAYS | SUM(WEEKEND DATES)
100 | 25 | 8
However this only works when I use a specific order number and cant' bring all order numbers in a sub query.
My Query:
SELECT SUM(Holiday_WKND_Flag), COUNT(*) FROM
(
SELECT
* FROM
BUSINESS_DATES
WHERE BUSINESS.Business BETWEEN (SELECT ORDER_DATE FROM ACTUAL_TABLE
WHERE ORDER# = '100'
)
AND
(SELECT CONTACT_DATE FROM ACTUAL_TABLE
WHERE ORDER# = '100'
)
TEMP
Uploading the table structure for your reference.
SELECT ORDER#, SUM(Holiday_WKND_Flag), COUNT(*)
FROM business_dates bd
INNER JOIN actual_table at ON bd.table_date BETWEEN at.order_date AND at.contact_date
GROUP BY ORDER#
Instead of joining on a BETWEEN (which always results in a bad Product Join) followed by a COUNT you better assign a bussines day number to each date (in best case this is calculated only once and added as a column to your calendar table). Then it's two Equi-Joins and no aggregation needed:
WITH cte AS
(
SELECT
Cast(table_date AS DATE) AS table_date,
-- assign a consecutive number to each busines day, i.e. not increased during weekends, etc.
Sum(CASE WHEN Holiday_WKND_Flag = 1 THEN 0 ELSE 1 end)
Over (ORDER BY table_date
ROWS Unbounded Preceding) AS business_day_nbr
FROM business_dates
)
SELECT ORDER#,
Cast(t.contact_date AS DATE) - Cast(t.order_date AS DATE) AS #_of_days
b2.business_day_nbr - b1.business_day_nbr AS #_of_business_days
FROM actual_table AS t
JOIN cte AS b1
ON Cast(t.order_date AS DATE) = b1.table_date
JOIN cte AS b2
ON Cast(t.contact_date AS DATE) = b2.table_date
Btw, why are table_date and order_date timestamp instead of a date?
Porting from Oracle?
You can use this query. Hope it helps
select order#,
order_date,
contact_date,
(select count(1)
from business_dates_table
where table_date between a.order_date and a.contact_date
and holiday_wknd_flag = 0
) business_days
from actual_table a

How to get weeks between two dates using calendar table?

I have the table table1 with two columns
start_date end_date
03/09/2016 03/15/2016
Now I need all the week start and end dates between these two dates
week_start_date week_end_date
03/07/2016 03/11/2016
03/14/2016 03/18/2016
I have the calendar table with dates and week start and enddates from jan 11.
I am trying to join with it, but its not producing the desired result.
SELECT DISTINCT r.START_DATE, r.END_DATE, c.week_start_date, c.week_end_date
FROM [table1] AS r
LEFT JOIN [Calendar] AS c
ON c.week_start_date BETWEEN r.WEEK_START_DATE AND r.WEEK_END_DATE
How can I achieve this using sql query. No procedures or t-sql please or variables.
I think the problem is the logic in the on clause:
select distinct r.START_DATE, r.END_DATE, c.week_start_date,c .week_end_date
from table1 r join
calendar c
on c.week_start_date <= r.end_date and
c.week_end_date >= r.start_date;
Notes:
The select distinct should be unnecessary (unless the calendar table is by day).
The left join is unnecessary.