HOW to calculate percent difference with lag in Postgresql - sql

I want to calculate the difference in percent for the number of visitors in the last 4 weeks (week on week) for a restaurant.
My code lets me group days into weeks and sum the number of visitors into each week, then I used lag and over to try and get the percent difference but it's giving me rubbish for that column.
Here's my code
SELECT
to_char(visit_date, 'IW') AS weeks, SUM(reserve_visitors) AS total_visitors,
((SUM(reserve_visitors)/lag(SUM(reserve_visitors), 1) OVER (ORDER BY to_char(visit_date, 'IW'))) -1) * 100 AS percentage_change
FROM res_visitors
WHERE visit_date BETWEEN '02/01/2017' AND '28/05/2017'
GROUP BY weeks
ORDER BY weeks DESC
LIMIT 4
This is what I get
Does anyone know where the error might be?
Ideally I'd like to have a percentage which shows how much the number of visitors grew/shrank from one week to the next one
Thanks in advance and sorry if it might seem trivial to most of you here, I've gone around trying to figure it out but I just can't seem to find it

Turns out the data type was wrong, I was dividing integers so any value under 0.5 is 0 and over 0.5 is 1.
I multiplied SUM(reserve_visitors) by 1.0 to make it a float and problem solved

Related

Calculate the only necessary difference and Group by between two Timestamps in PostgreSQL

I see similar question but didn't find helpful answer for my problem.
I have one query:
select au.username
,ej.id as "job_id"
,max(ec."timestamp") as "last_commit"
,min(ec."timestamp") as "first_commit"
,age(max(ec."timestamp"), min(ec."timestamp")) as "diff as age"
,to_char(age(max(ec."timestamp")::timestamp, min(ec."timestamp")::timestamp),'HH:MI:SS') as "diff as char"
,et.id as "task_id"
from table and etc..
And that my output(Sorry for picture but its best view):
So, as you can see I have timestamp with zones, and I trying calculate difference between last_commit and first_commit. Within function age its goes well, but I need extract only hours and minutes from this subtraction. N.B! only hours and minutes not days for example job_id=1 first row, the difference is 2 minutes and 42 seconds and where job_id=2 second row, the difference is 2 hours and 2 minutes and 55 sec, not 16 days X 24 hours, I don't need calculate days. When I try to_char its return not exactly what I expect. Last two columns within green color in my picture, show what I expect and want. So for every row calculate difference between last and first commit included only hours and minutes (in other words calculate only time not dates) and calculate total sum by task_id as represent in last column in pic.
Thanks.
try this :
SELECT age(max(ec."timestamp"), min(ec."timestamp")) - date_trunc('day', age(max(ec."timestamp"), min(ec."timestamp")))
You can try converting a Timestamp type to just time, like in this answer.
The result of string SQL is:
select au.username
,ej.id as "job_id"
,max(ec."timestamp") as "last_commit"
,min(ec."timestamp") as "first_commit"
,(max(ec."timestamp")::time-min(ec."timestamp")::time) as "diff as age"
,to_char(age(max(ec."timestamp")::timestamp, min(ec."timestamp")::timestamp),'HH:MI:SS') as "diff as char"
,et.id as "task_id"
There are otres possible solutions working with timestamp, but this one i consider simple.

SQL - Finding Percent Of a Total and subtracting to get two new totals

In my SQL course I'm trying to answer a problem in which i'm being asked to find X% of a Total then subtracting that result from the original total to produce another result. Then putting these results (the X% of the total and the total-X% of total) in two new columns.
Example: We need to know how much money we owe Tom and Ted. We have total up sales to $1,000,000.00. We owe Tom 75% of that total. The remainder goes to Ted.
I can't seem to find anything in my readings/videos about this nor a google search that isn't an answers that produces ratios or comparing to other records in the table. Also, not sure about how to get the results into their own columns. Thanks for any advice!
Example of what I got so far:
SELECT SUM(Sale_Amount) From Order_Table
Now I have to find the % of that SUM then subtract it from the SUM and push both results to two new columns, one for the percent of the SUM(Sale_Amount) and one for the remainder.
Given it's an SQL course (and it's not 100% clear what's being asked), I'm not going to give you the total answer, but I'll give you components but you'll need to understand them to put them together.
In SQL, you can
Get totals using SUM and GROUP BY
Do normal maths e.g., SELECT 10000 * 60/100 to get percentages of totals
'Save' results by a) having columns/fields to save them in, and b) UPDATE those fields with relevant data
Note if you're not saving data, and simply reporting them, you can just add those to a SELECT statement e.g., SELECT 100000 AS Total, 100000 * 0.75 AS Toms_Share, 100000 * 0.25 AS Teds_Share.

SSAS (Tabular) / DAX - Calculate measure over time / Rolling distinct count

I've a question about a rolling distinct count. I'm trying to calculate the latest 30 weeks (210 days) from a specific date (eg. Specific date = 18-02-2019 distinct count from 23-07-2018).
I've found a website/blog where this is explained, https://radacad.com/datesinperiod-vs-datesbetween-dax-time-intelligence-for-power-bi. But in some weird way, my calculation is not working.
My DAX expression:
Aantal mutaties afgelopen 30 weken:=
CALCULATE(
DISTINCTCOUNT(FCT_KlantReis_Mutatie[Mutatie]);
DATESINPERIOD(
FCT_KlantReis_Mutatie[Mutatiedatum];
LASTDATE(FCT_KlantReis_Mutatie[Mutatiedatum]) ;-210;DAY)
)
But in Excel (and PowerBI) I get the following result:
The table is linked to a date dimension. My guess is that it must be posible, but how...
Thanks in advance for the help.

SQL Average of total days in DATA per month

I have a SQL question.
I am trying to find the average injection volume per month. Currently my code takes the sum of all days of injection, and divides them by the TOTAL DAYS in the month.
Sum(W1."INJECTION_VOLUME" /
EXTRACT(DAY FROM LAST_DAY(W1."INJECTION_DATE"))) AS "AVGINJ"
This is not what I wanted.
I need to take the injection_volume and divide by the total days in the DATA .
ie. right now the data only 8 days of injection volume, lets say it is 3000.
So right now the sql is 3000/31.
I need to have it be 3000/8 (the total days in the data for the current month.)
Also, this should only be for the current month. All other completed months should be divided by the total days in the month.
Use
SELECT
SUM(W1.INJECTION_VOLUME) / COUNT(DISTINCT MyDateField)
FROM MyTable
WHERE X=Value
This gives you what you're after
SUM(W1.INJECTION_VOLUME) is the total volume for the dataset
Gives you the number of days, no matter how many records you have
COUNT(DISTINCT MyDateField)
So if you have 100 records but only 5 actual unique days in this time, this expression gives you 5
Note that this kind of calc is normally worked out with
SUM(A) / SUM(B)
not
SUM(A/B)
They give you completely different answers.
In order to get the average of the data for the current month you will need to divide by the count in the month:
SUM(`W1`.`INJECTION_VOLUME` / COUNT(EXTRACT(YEAR_MONTH FROM `W1`.`INJECTION_DATE`)))
To get all other data as the full month you'll need to combine your code:
SUM(`W1`.`INJECTION_VOLUME` / EXTRACT(DAY FROM LAST_DAY(`W1`.`INJECTION_DATE`)))
With an IF. So something like this:
SUM(
IF(
EXTRACT(YEAR_MONTH FROM `W1`.`INJECTION_DATE`) = EXTRACT(YEAR_MONTH FROM NOW()),
`W1`.`INJECTION_VOLUME` / COUNT(EXTRACT(YEAR_MONTH FROM `W1`.`INJECTION_DATE`)),
`W1`.`INJECTION_VOLUME` / EXTRACT(DAY FROM LAST_DAY(`W1`.`INJECTION_DATE`)
)
)
Note: this is untested and I'm not sure about the RDBMS you are using so you may need to change the code slightly to make it work.

Query to find a weekly average

I have an SQLite database with the following fields for example:
date (yyyymmdd fomrat)
total (0.00 format)
There is typically 2 months of records in the database. Does anyone know a SQL query to find a weekly average?
I could easily just execute:
SELECT COUNT(1) as total_records, SUM(total) as total FROM stats_adsense
Then just divide total by 7 but unless there is exactly x days that are divisible by 7 in the db I don't think it will be very accurate, especially if there is less than 7 days of records.
To get a daily summary it's obviously just total / total_records.
Can anyone help me out with this?
You could try something like this:
SELECT strftime('%W', thedate) theweek, avg(total) theaverage
FROM table GROUP BY strftime('%W', thedate)
I'm not sure how the syntax would work in SQLite, but one way would be to parse out the date parts of each [date] field, and then specifying which WEEK and DAY boundaries in your WHERE clause and then GROUP by the week. This will give you a true average regardless of whether there are rows or not.
Something like this (using T-SQL):
SELECT DATEPART(w, theDate), Avg(theAmount) as Average
FROM Table
GROUP BY DATEPART(w, theDate)
This will return a row for every week. You could filter it in your WHERE clause to restrict it to a given date range.
Hope this helps.
Your weekly average is
daily * 7
Obviously this doesn't take in to account specific weeks, but you can get that by narrowing the result set in a date range.
You'll have to omit those records in the addition which don't belong to a full week. So, prior to summing up, you'll have to find the min and max of the dates, manipulate them such that they form "whole" weeks, and then run your original query with a WHERE that limits the date values according to the new range. Maybe you can even put all this into one query. I'll leave that up to you. ;-)
Those values which are "truncated" are not used then, obviously. If there's not enough values for a week at all, there's no result at all. But there's no solution to that, apparently.