I have a table in GBQ in the following format :
UserId Orders Month
XDT 23 1
XDT 0 4
FKR 3 6
GHR 23 4
... ... ...
It shows the number of orders per user and month.
I want to calculate the percentage of users who have orders, I did it as following :
SELECT
HasOrders,
ROUND(COUNT(*) * 100 / CAST( SUM(COUNT(*)) OVER () AS float64), 2) Parts
FROM (
SELECT
*,
CASE WHEN Orders = 0 THEN 0 ELSE 1 END AS HasOrders
FROM `Table` )
GROUP BY
HasOrders
ORDER BY
Parts
It gives me the following result:
HasOrders Parts
0 35
1 65
I need to calculate the percentage of users who have orders, by month, in a way that every month = 100%
Currently to do this I execute the query once per month, which is not practical :
SELECT
HasOrders,
ROUND(COUNT(*) * 100 / CAST( SUM(COUNT(*)) OVER () AS float64), 2) Parts
FROM (
SELECT
*,
CASE WHEN Orders = 0 THEN 0 ELSE 1 END AS HasOrders
FROM `Table` )
WHERE Month = 1
GROUP BY
HasOrders
ORDER BY
Parts
Is there a way execute a query once and have this result ?
HasOrders Parts Month
0 25 1
1 75 1
0 45 2
1 55 2
... ... ...
SELECT
SIGN(Orders),
ROUND(COUNT(*) * 100.000 / SUM(COUNT(*), 2) OVER (PARTITION BY Month)) AS Parts,
Month
FROM T
GROUP BY Month, SIGN(Orders)
ORDER BY Month, SIGN(Orders)
Demo on Postgres:
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=4cd2d1455673469c2dfc060eccea8020
You've stated that it's important for the total to be 100% so you might consider rounding down in the case of no orders and rounding up in the case of has orders for those scenarios where the percentages falls precisely on an odd multiple of 0.5%. Or perhaps rounding toward even or round smallest down would be better options:
WITH DATA AS (
SELECT SIGN(Orders) AS HasOrders, Month,
COUNT(*) * 10000.000 / SUM(COUNT(*)) OVER (PARTITION BY Month) AS PartsPercent
FROM T
GROUP BY Month, SIGN(Orders)
ORDER BY Month, SIGN(Orders)
)
select HasOrders, Month, PartsPercent,
PartsPercent - TRUNCATE(PartsPercent) AS Fraction,
CASE WHEN HasOrders = 0
THEN FLOOR(PartsPercent) ELSE CEILING(PartsPercent)
END AS PartsRound0Down,
CASE WHEN PartsPercent - TRUNCATE(PartsPercent) = 0.5
AND MOD(TRUNCATE(PartsPercent), 2) = 0
THEN FLOOR(PartsPercent) ELSE ROUND(PartsPercent) -- halfway up
END AS PartsRoundTowardEven,
CASE WHEN PartsPercent - TRUNCATE(PartsPercent) = 0.5 AND PartsPercent < 50
THEN FLOOR(PartsPercent) ELSE ROUND(PartsPercent) -- halfway up
END AS PartsSmallestTowardZero
from DATA
It's usually not advisable to test floating-point values for equality and I don't know how BigQuery's float64 will work with the comparison against 0.5. One half is nevertheless representable in binary. See these in a case where the breakout is 101 vs 99. I don't have immediate access to BigQuery so be aware that Postgres's rounding behavior is different:
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=c8237e272427a0d1114c3d8056a01a09
Consider below approach
select hasOrders, round(100 * parts, 2) as parts, month from (
select month,
countif(orders = 0) / count(*) `0`,
countif(orders > 0) / count(*) `1`,
from your_table
group by month
)
unpivot (parts for hasOrders in (`0`, `1`))
with output like below
I have 3 queries:
the first one calculate Totals per Qtr and
the other two calculate Totals per Qtr where Receipt Field is [Yes] or [No].
Now I have(example):
qtrTotals
Year / Total / TotalQtr1 / TotalQtr2 / etc...
qtrTotalsReceiptYes
Year / TotalYes / TotalYesQtr1 / TotalYesQtr2 / etc...
qtrTotalsReceiptNo
Year / TotalNo / TotalNoQtr1 / TotalNoQtr2 / etc...
Is it possible to make one query?
qtrTotals
Year / Total / TotalYes / TotalNo / TotalQtr1 / TotalYesQtr1 / TotalNoQtr1 / etc...
MySQL :
All:
TRANSFORM IIf(Sum([price]) Is Null,0,Sum([price])) AS SumPrice
SELECT Format([ExpencesDate],"yyyy") AS [Year], IIf(Sum([SumPrice]) Is Null,0,Sum([SumPrice])) AS TotalPricePerYear
FROM tblExpences
GROUP BY Format([ExpencesDate],"yyyy")
ORDER BY Format([ExpencesDate],"yyyy") DESC
PIVOT Month([ExpencesDate]) In (1,2,3,4,5,6,7,8,9,10,11,12);
Yes:
TRANSFORM IIf(Sum([price]) Is Null,0,Sum([price])) AS SumPrice
SELECT Format([ExpencesDate],"yyyy") AS [Year], IIf(Sum([SumPrice]) Is Null,0,Sum([SumPrice])) AS TotalPricePerYear
FROM tblExpences
WHERE (((tblExpences.ReceiptYesNo)="Yes"))
GROUP BY Format([ExpencesDate],"yyyy")
ORDER BY Format([ExpencesDate],"yyyy") DESC
PIVOT Month([ExpencesDate]) In (1,2,3,4,5,6,7,8,9,10,11,12);
No:
TRANSFORM IIf(Sum([price]) Is Null,0,Sum([price])) AS SumPrice
SELECT Format([ExpencesDate],"yyyy") AS [Year], IIf(Sum([SumPrice]) Is Null,0,Sum([SumPrice])) AS TotalPricePerYear
FROM tblExpences
WHERE (((tblExpences.ReceiptYesNo)="No"))
GROUP BY Format([ExpencesDate],"yyyy")
ORDER BY Format([ExpencesDate],"yyyy") DESC
PIVOT Month([ExpencesDate]) In (1,2,3,4,5,6,7,8,9,10,11,12);
Thank you.
PS.
The tblExpences (Correct Expenses) has [Date] / [Price] / [ReceiptYesNo].
tblExpences
10/3/2017 / 200 / Yes
10/3/2017 / 200 / No
11/3/2017 / 100 / Yes
14/3/2017 / 100 / No
15/4/2017 / 200 / Yes
10/5/2017 / 200 / No
TLDR; Here is a general form how you can make it work.
Select *
From (Query1) as Q1
Join (Query2) as Q2 On 1
Join (Query3) as Q3 On 1;
It should work because the 3 queries are using an aggregation function only thus returning a single row. Therefore, always joining these columns will result in each column joining and forming a single row of multiple columns.
Okay, a different approach. Firstly, I've assumed your three queries are saved as: qryTotalTotal, qryTotalYes, qryTotalNo.
SELECT qryTotalTotal.Year,
qryTotalTotal.TotalPricePerYear AS TotalPerYear,
qryTotalYes.TotalPricePerYear AS TotalPerYearYes,
qryTotalNo.TotalPricePerYear AS TotalPerYearNo,
qryTotalYes.[1]+qryTotalNo.[1] as TotalMonth1,
qryTotalYes.[1] as TotalMonthYes1,
qryTotalNo.[1] as TotalMonthNo1,
qryTotalYes.[2]+qryTotalNo.[2] as TotalMonth2,
qryTotalYes.[2] as TotalMonthYes2,
qryTotalNo.[2] as TotalMonthNo2,
qryTotalYes.[3]+qryTotalNo.[3] as TotalMonth3,
qryTotalYes.[3] as TotalMonthYes3,
qryTotalNo.[3] as TotalMonthNo3,
qryTotalYes.[4]+qryTotalNo.[4] as TotalMonth4,
qryTotalYes.[4] as TotalMonthYes4,
qryTotalNo.[4] as TotalMonthNo4,
qryTotalYes.[5]+qryTotalNo.[5] as TotalMonth5,
qryTotalYes.[5] as TotalMonthYes5,
qryTotalNo.[5] as TotalMonthNo5,
qryTotalYes.[6]+qryTotalNo.[6] as TotalMonth6,
qryTotalYes.[6] as TotalMonthYes6,
qryTotalNo.[6] as TotalMonthNo6,
qryTotalYes.[7]+qryTotalNo.[7] as TotalMonth7,
qryTotalYes.[7] as TotalMonthYes7,
qryTotalNo.[7] as TotalMonthNo7,
qryTotalYes.[8]+qryTotalNo.[8] as TotalMonth8,
qryTotalYes.[8] as TotalMonthYes8,
qryTotalNo.[8] as TotalMonthNo8,
qryTotalYes.[9]+qryTotalNo.[9] as TotalMonth9,
qryTotalYes.[9] as TotalMonthYes9,
qryTotalNo.[9] as TotalMonthNo9,
qryTotalYes.[10]+qryTotalNo.[10] as TotalMonth10,
qryTotalYes.[10] as TotalMonthYes10,
qryTotalNo.[10] as TotalMonthNo10,
qryTotalYes.[11]+qryTotalNo.[11] as TotalMonth11,
qryTotalYes.[11] as TotalMonthYes11,
qryTotalNo.[11] as TotalMonthNo11,
qryTotalYes.[12]+qryTotalNo.[12] as TotalMonth12,
qryTotalYes.[12] as TotalMonthYes12,
qryTotalNo.[12] as TotalMonthNo12
FROM (qryTotalTotal LEFT JOIN qryTotalYes ON qryTotalTotal.Year = qryTotalYes.Year)
LEFT JOIN qryTotalNo ON qryTotalTotal.Year = qryTotalNo.Year;
To my mind your queries and the output you say they give don't agree with each other. It seems like you must do something to combine your months into quarters.
Anyway, in similar style to your second and third queries:
TRANSFORM IIf(Sum([Price]) Is Null,0,Sum([Price])) AS SumPrice
SELECT Year([ExpensesDate]) AS [Year]
FROM tblExpenses, Numbers
WHERE (((Numbers.Number) Between 1 And 4))
GROUP BY Year([ExpensesDate])
PIVOT IIf([Number]=1,"TotalMonth"& [ReceiptYesNo] & Month([ExpensesDate]),IIf([Number]=2,"TotalMonth" & Month([ExpensesDate]),IIf([Number]=3,"TotalPerYear" & [ReceiptYesNo],"TotalPerYear"))) in ("TotalPerYear","TotalPerYearYes","TotalPerYearNo","TotalMonth1","TotalMonthYes1","TotalMonthNo1","TotalMonth2","TotalMonthYes2","TotalMonthNo2","TotalMonth3","TotalMonthYes3","TotalMonthNo3","TotalMonth4","TotalMonthYes4","TotalMonthNo4","TotalMonth5","TotalMonthYes5","TotalMonthNo5","TotalMonth6","TotalMonthYes6","TotalMonthNo6","TotalMonth7","TotalMonthYes7","TotalMonthNo7","TotalMonth8","TotalMonthYes8","TotalMonthNo8","TotalMonth9","TotalMonthYes9","TotalMonthNo9","TotalMonth10","TotalMonthYes10","TotalMonthNo10","TotalMonth11","TotalMonthYes11","TotalMonthNo11","TotalMonth12","TotalMonthYes12","TotalMonthNo12");
I found I had to paste this into a new query as it kept remembering old sort orders for the column headings.
This depends on a new table called Numbers. This needs just a single field called Number and should be populated with (at least) four rows of data holding the numbers: 1, 2, 3 and 4. Like this:
Table: Numbers
Number
------
1
2
3
4
NB: I corrected the spelling of 'Expense', which will mean you either need to tweak your data or my query so they agree.
EDIT
the values in the table can be negative numbers (sorry for the oversight when asking the question)
Having exhausted all search efforts, I am very stuck with the following:
I would like to calculate a running total based on the initial value. For instance:
My table would look like:
Year Percent Constant
==== ===== ========
2000 1.40 100
2001 -1.08 100
2002 1.30 100
And the desired results would be:
Year Percent Constant RunningTotal
==== ====== ======== ============
2000 1.40 100 140
2001 -1.08 100 128.8
2002 1.30 100 167.44
Taking the calculated value of 1.40*100 and multiplying it with percent of the next line, 1.08 and so on.
I am using Sql Server 2012. I've looked into using a common table expression, but can't seem to get the correct syntax sadly.
In SQL Server 2012+, you would use a cumulative sum:
select t.*,
(const * sum(1 + percent / 100) over (order by year)) as rolling_sum
from t
order by t.year;
EDIT:
Ooops, I notice you really seem to want a cumulative product. Assuming percent is always greater than 0, then just use logs:
select t.*,
(const * exp(sum(log(1 + percent / 100)) over (order by year))) as rolling_product
from t
order by t.year;
You can accomplish this task using a recursive CTE
;WITH values_cte AS (
SELECT [Year]
,[Percent]
,[Constant]
,CASE WHEN [v].[Percent] < 0 THEN
[v].[Constant] - (([v].[Percent] + 1) * [v].[Constant])
ELSE
[v].[Percent] * [v].[Constant]
END
AS [RunningTotal]
FROM [#tmp_Values] v
WHERE [v].[Year] = 2000
UNION ALL
SELECT v2.[Year]
,v2.[Percent]
,v2.[Constant]
,CASE WHEN [v2].[Percent] < 0 THEN
[v].[RunningTotal] + (([v2].[Percent] + 1) * [v].[RunningTotal])
ELSE
[v2].[Percent] * [v].[RunningTotal]
END
AS [RunningTotal]
FROM values_cte v
INNER JOIN [#tmp_Values] v2 ON v2.[Year] = v.[Year] + 1
)
SELECT *
FROM [values_cte]
use LEAD keyword
SELECT
Year
, Percent
, Constant
, Percent * Constant * (LEAD(Percent) OVER(ORDER BY Year)) as RunningTotal
FROMYourTable
this is new keyword from MSSQL 2012
I have 2 columns from a table and i want to add a third column to output the result of a calculation
select statement at the moment is:
select revenue, cost
from costdata
my 2 columns are revenue and cost
table name: costdata
my formula is: = ((revenue - cost)/ revenue)*100
I want the third column to be named 'result'
any idea on how to do this in a select statement?
SELECT revenue
, cost
, ((revenue - cost) / revenue) * 100 As result
FROM costdata
You mentioned in the comments that you get a divide by zero error. This wll occur when revenue equals zero.
What you want to happen in this scenario is up to you but this should get you started
SELECT revenue
, cost
, CASE WHEN revenue = 0 THEN
0
ELSE
((revenue - cost) / revenue) * 100
END As result
FROM costdata
Query:
SELECT revenue,
cost,
CASE WHEN revenue <> 0
THEN ((revenue - cost) / revenue) * 100
ELSE 0 END As result
FROM costdata
Try,
select revenue, cost,((revenue - cost)/ revenue)*100 AS result
from costdata
SELECT revenue, cost, ((revenue - cost)/ revenue)*100 AS result FROM costdata