SQL Query to Count Daily Totals Skips Days - sql

This query counts the amount of bottles we produce over a month and groups them by day. If there are no bottles produces that day then it is skipped from the output instead of returning 0 bottles produced. How can I return with the day's timestamp if there are no bottles produced? I heard the calendar table has to be used for this.
SELECT CONVERT(datetime,CAST(t_stamp AS DATE)), COUNT(bottles) AS 'Good Bottles'
FROM bottles
WHERE t_stamp
BETWEEN "any date"
AND "any date"
GROUP BY CAST(t_stamp AS DATE)
ORDER BY CAST(t_stamp AS DATE) ASC
Current Output:
Aug 12, 2019 12:00 am..................4302
Aug 13, 2019 12:00 am..................2302
Aug 17, 2019 12:00 am..................1302
Aug 18, 2019 12:00 am..................4302
Desired Output:
Aug 12, 2019 12:00 am..................4302
Aug 13, 2019 12:00 am..................2302
Aug 14, 2019 12:00 am..................0
Aug 15, 2019 12:00 am..................0
Aug 16, 2019 12:00 am..................0
Aug 17, 2019 12:00 am..................1302
Aug 18, 2019 12:00 am..................4302

You need to generate the days. A pretty simple method uses a recursive CTE:
WITH dates as (
SELECT CONVERT(date, "any date1") as dte
UNION ALL
SELECT DATEADD(day, 1, dte)
FROM dates
WHERE dte < "any date2"
)
SELECT d.dte, COUNT(bottles) AS GoodBottles
FROM dates d LEFT JOIN
bottles b
ON CAST(t_stamp as DATE) = d.dte
GROUP BY d.dte
ORDER BY d.dte ASC;
Notes:
If you have a calendar or tally table, then use that instead.
If the number of dates exceed 100, you need to add OPTION (MAXRECURSION 0).
COUNT(bottles) looks suspicious. Do you really intend SUM(bottles)?
Converting a column to a date and then to a datetime is also suspicious. It is unclear why you would want a datetime for the first column.

Related

How to find the day name?

I have a table named nifty_50 with the below two columns.
Date Close
Apr 07, 2022 17,763.40
Apr 06, 2022 17,807.65
Apr 05, 2022 17,957.40
Apr 04, 2022 18,053.40
Apr 01, 2022 17,670.45
Mar 31, 2022 17,464.75
I am trying to add another column which says the day name of the Date column.
Expected Output:
Date Close Day_name
Apr 07, 2022 17,763.40 Thursday
Apr 06, 2022 17,807.65 Wednesday
Apr 05, 2022 17,957.40 Tuesday
Apr 04, 2022 18,053.40 Monday
Apr 01, 2022 17,670.45 Friday
Mar 31, 2022 17,464.75 Thursday
I tried doing
select date, close, datename(date ,getdate()) as day_name, from nifty_50;
The above code doesn't work and all the other codes which i googled and tried also don't work. I know this is a simple code. can someone please help me with this?
Use the TO_CHAR function with the Day format model.
select "DATE",
close,
TO_CHAR("DATE", 'fmDay') as day_name
from nifty_50;
Note: fmDay will strip trailing spaces from the day names (otherwise the days will all be output as strings of length equal to the longest day name padded with trailing spaces).
Note 2: DATE is a reserved word in Oracle and cannot be used as an unquoted identifier. It is better practice to pick a different identifier instead of using reserved words.
Which, for the sample data:
CREATE TABLE nifty_50 ("DATE", Close) AS
SELECT DATE '2022-04-07', 17763.40 FROM DUAL UNION ALL
SELECT DATE '2022-04-06', 17807.65 FROM DUAL UNION ALL
SELECT DATE '2022-04-05', 17957.40 FROM DUAL UNION ALL
SELECT DATE '2022-04-04', 18053.40 FROM DUAL UNION ALL
SELECT DATE '2022-04-01', 17670.45 FROM DUAL UNION ALL
SELECT DATE '2022-03-31', 17464.75 FROM DUAL;
Outputs:
DATE
CLOSE
DAY_NAME
2022-04-07 00:00:00
17763.4
Thursday
2022-04-06 00:00:00
17807.65
Wednesday
2022-04-05 00:00:00
17957.4
Tuesday
2022-04-04 00:00:00
18053.4
Monday
2022-04-01 00:00:00
17670.45
Friday
2022-03-31 00:00:00
17464.75
Thursday
db<>fiddle here
You can try below to fetch Day name:
DECLARE #DateVal DATE = '2022-07-04';
SELECT #DateVal As [Date],
DATENAME(WEEKDAY, #DateVal) AS [Day Name],
DATENAME(DW, #DateVal) AS [Day Name],
DATENAME(W, #DateVal) AS [Day Name];

Bigquery convert ''Jan 30 2016 12:00AM" to date

I'm attempting to convert a string to a timestamp within Bigquery. The question is really simple, how do I convert this string Jan 30 2016 12:00AM or Aug 9 2015 12:00AM to date?
I have tried referring to the Bigquery documentation but it didn't seem to work:
(https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions#parse_date)
select PARSE_DATE('%b %e %E4Y', 'Jan 30 2016 12:00AM')
select PARSE_DATE('%b %e %E4Y', 'Aug 9 2015 12:00AM')
Your input string is actually a timestamp, not a date, because it has a time component at the end. So, consider using PARSE_TIMESTAMP instead:
SELECT PARSE_TIMESTAMP('%b %e %E4Y %I:%M%p', 'Jan 30 2016 12:00AM') AS ts_out
FROM yourTable;
This would return a timestamp based on the input string. If you really want a date, you could cast the above to date, or you could just use LEFT on the string input to restrict to only the date portion:
SELECT PARSE_DATE('%b %e %E4Y', LEFT('Jan 30 2016 12:00AM', 11)) AS ts_out
FROM yourTable;
Below is for BigQuery Standard SQL
SELECT DATE(PARSE_TIMESTAMP('%b %e %Y %R%p', ts))
You can test it with dummy data as in below example
#standardSQL
WITH `project.dataset.table` AS (
SELECT 'Jan 30 2016 12:00AM' ts UNION ALL
SELECT 'Aug 9 2015 12:00AM' UNION ALL
SELECT 'Aug 9 2015 12:00AM'
)
SELECT ts, DATE(PARSE_TIMESTAMP('%b %e %Y %R%p', ts)) date_from_ts
FROM `project.dataset.table`
with result
Row ts date_from_ts
1 Jan 30 2016 12:00AM 2016-01-30
2 Aug 9 2015 12:00AM 2015-08-09
3 Aug 9 2015 12:00AM 2015-08-09

How can compute monthly average price of an invoice in ORACLE (Varray&loop)

I have a table for invoices and there are millions of data. In my table, there are invoices and their first and last dates for customers. My target is to compute monthly average price of the invoices. For instance i have:
CUSTOMER_ID INVOICE_ID FIRST_DATE LAST_DATE AMOUNT_OF_INVOICE
9876543 1a 1 Jan 2017 17 Jan 2017 32$
9876543 1b 17 Jan 2017 10 Feb 2017 72$
9876543 1c 10 Feb 2017 7 March 2017 100$
9876543 1d 7 March 2017 1 April 2017 25$
9870011 2a 1 Jan 2017 10 Jan 2017 18$
9870011 2b 10 Jan 2017 10 Feb 2017 62$
9870011 2c 10 Feb 2017 1 April 2017 50$
my target is:
CUSTOMER_ID MONTH MONTHLY_AVERAGE_PRICE
9876543 January 2017 77$ (=16x2+15x3)
9876543 February 2017 103$ (=9x3+19x4)
9876543 March 2017 49$ (=6x4+25x1)
9870011 January 2017 62$ (=9x2+22x2)
9870011 February 2017 37$ (=9x2+19x1)
9870011 March 2017 31$ (=31x1)
For instance I compute 77$ (=16x2+15x3) by:
First invoice which INVOICE_ID is 1a there are 16 days from 1 Jan 2017 to 17 Jan 2017 (not incuding 17 Jan). And the price of invoice is 32$. Therefore average price for one day is 32/16 = 2$. The second invoice is 1b and there are 24 days from 17 Jan 2017 to 10 Feb 2017. Therefore average consumption per day is 3$. And the part of this invoice for January is 15 days (From 17 January to 31 January including 31 January). All in all, for January average consumption: 16x2$+15x3$=77$.
Here I think, I have to use varray for storage the data on months and I have to use a loop to find the days between FIRST_DATE and LAST_DATE. However I couldn't do it. Or are there in other ways?
Oracle Query:
WITH month_invoices ( c_id, i_id, first_date, last_date, month_start, month_end, amount )
AS (
SELECT customer_id,
invoice_id,
first_date,
last_date,
first_date,
LEAST( ADD_MONTHS( TRUNC( first_date, 'MM' ), 1 ), last_date ),
amount_of_invoice
FROM your_table
UNION ALL
SELECT c_id,
i_id,
first_date,
last_date,
month_end,
LEAST( ADD_MONTHS( month_end, 1 ), last_date ),
amount
FROM month_invoices
WHERE month_end < last_date
)
SELECT c_id AS customer_id,
TRUNC( month_start, 'MM' ) AS month,
SUM( amount * ( month_end - month_start ) / ( last_date - first_date ) )
AS average_monthly_price
FROM month_invoices
GROUP BY c_id, TRUNC( month_start, 'MM' )
ORDER BY customer_id, month;
Output:
CUSTOMER_ID MONTH AVERAGE_MONTHLY_PRICE
----------- ---------- ---------------------
9876543 2017-01-01 77
9876543 2017-02-01 103
9876543 2017-03-01 49
9870011 2017-01-01 62
9870011 2017-02-01 37
9870011 2017-03-01 31
This is what I came up with.
The inner query creates a row for each day of each invoice.
The outer query sums them up.
It assumes that invoices will only be a maximum of 999 days long.
select customer_id, month, sum(average_cost_per_day) average_cost_per_day
from (
select max(customer_id) customer_id,
invoice_id,
to_char(first_date + n-1, 'MONTH YYYY') month,
count(1)*max(amount_of_invoice)/max(last_date-first_date) average_cost_per_day
from your_table
inner join (
select level n
from dual
connect by level <= 1000
)
on (first_date + n-1 < last_date)
group by invoice_id, to_char(first_date + n-1, 'MONTH YYYY')
)
group by customer_id, month
order by customer_id desc, to_date(month,'MONTH YYYY');

Add column for Fiscal Week in an SQL SELECT Statement

Below mentioned is my Query:
SELECT DPSNumber, StatusDateTime FROM DispatchTool
The Resulst is:
DPSNumber StatusDateTime
123123526 8/4/14 12:00 AM
123123527 8/5/14 12:00 AM
123123528 8/6/14 12:00 AM
123123529 8/7/14 12:00 AM
I want to add an additional column to this result as shown below:
DPSNumber StatusDateTime FiscalWeek
123123526 8/4/14 12:00 AM 27
123123527 8/5/14 12:00 AM 27
123123528 8/6/14 12:00 AM 27
123123529 8/7/14 12:00 AM 27
Fiscal Week for my Organization started on January 31, 2014
Looks like DateDiff Function is what you need
SELECT DPSNumber,
StatusDateTime,
Datediff(wk, CONVERT(DATE, 'January 31, 2014'), CONVERT(DATE, StatusDateTime)) FiscalWeek
From Tablename

oracle month to day

I have data as below in which data is splitted as below where month 1 represent JAN ,Month 2 represent FEB and so on.
MONTH VALUE
1 93
2 56
3 186
4 60
Now I need to calculate sum of value based on number of days.
Ex- If date is between Jan 1st to March 31st then SUM is 335(93+56+186)
If date is between Jan 17th to March 31st then sum is 287(45+56+186) .
Here 45 for month of january is dervied from average per day for month of JAN (93/31==3) .Multiplied by number of days in January for the required period.
Ignore leap year and FEB month can be taken 28 days always.
As one of the approaches, you can turn a month into a list of days(dates) that constitute it (ease filtering operation), and perform calculation as follows:
/* sample of data that you've provided */
with t1(mnth,val) as(
select 1, 93 from dual union all
select 2, 56 from dual union all
select 3, 186 from dual union all
select 4, 60 from dual
),
/*
Generates current year dates
From January 1st 2014 to December 31st 2014
*/
dates(dt) as(
select trunc(sysdate, 'YEAR') - 1 + level
from dual
connect by extract(year from (trunc(sysdate, 'YEAR') - 1 + level)) <=
extract(year from sysdate)
)
/*
The query that performs calculations based on range of dates
*/
select sum(val / extract(day from last_day(dt))) as result
from dates d
join t1
on (extract(month from d.dt) = t1.mnth)
where dt between date '2014-01-17' and -- January 17th 2014 to
date '2014-03-31' -- March 31st 2014
Result:
RESULT
----------
287