Tableau filter based on data from month 1 and month 1 + 1 - conditional-statements

I am trying to count number of ids which meet certain requirements:
over 1k income for month a
below 500 income for month a + 1
how do I achieve this in tableau? I tried using the following calculated filed:
If {fixed [id],month[date]: sum(income)} >=1000 and {fixed [id],month[date]+1: sum(income)} <500 then 1 else 0 end
But not sure whether such month(date) + 1 method worked here.

Just create a new Date field, shifted forward by 1 month:
DATEADD('month',1,[Order Date])
For both dates, right-click Custom-Date --> Month-Year, doing so you can create both Actaul and Shifted date.
Then you only need a calculated field like this in order to count all months with that condition:
sum(if { FIXED [Order Date (Month / Year)] : SUM([Sales])} >= 50000
and { FIXED [Order Date + 1 Month (Month / Year)] : SUM([Sales])} <= 100000
then 1
end
)

Related

SQL concat case select when trying to add new column of previous month data

I have a data set in which I need to concat month and year for the previous month. the problem is it spans over two years. I need to create a statement in which mean the month - 1 = 0, month becomes 12 and year-1.
Select concat(case
when month > 1 then select(month-1, year)
when month = 1 then select(12, year -1)
else select(month-1, year)
end
as monthyear
from table
You need 2 CASE statements inside concat(), for the month and the year:
select
concat(
case when month > 1 then month - 1 else 12 end,
case when month > 1 then year else year - 1 end
)
If you have month and year as separate columns and want to subtract one month, then you can use:
select (case when month > 1 then year else year - 1 end) as year,
(case when month > 1 then month - 1 else 12 end) as month
Here's a different approach (tried with SQLite3, adjust accordingly to your SQL syntax):
-- some test data first
create table t(yy,mm);
insert into t values
(2018,1),(2018,2),(2018,3),(2018,4),(2018,5),(2018,6),
(2018,7),(2018,8),(2018,9),(2018,10),(2018,11),(2018,12),
(2019,1),(2019,2),(2019,3),(2019,4),(2019,5),(2019,6),
(2019,7),(2019,8),(2019,9),(2019,10),(2019,11),(2019,12),
(2020,1),(2020,2),(2020,3),(2020,4),(2020,5),(2020,6),
(2020,7),(2020,8),(2020,9),(2020,10),(2020,11),(2020,12);
-- current year and month, year of previous month and previous month
select yy,mm,yy-((mm+10)%12+1)/12 as yy_1,(mm+10)%12+1 mm_1 from t;

sql repeat rows for weekend and holidays

I have a table A that we import based on the day that it lands on a location. We dont receive files on weekend and public holidays, and the table has multiple countries data so the public holidays vary. In essence we looking to duplicate a row multiple times till it encounters the next record for that ID (unless its the max date for that ID). A typical record looks like this:
Account Datekey Balance
1 20181012 100
1 20181112 100
1 20181212 100
1 20181512 100
1 20181712 100
And needs to look like this (sat, sun & PH added to indicate the day of week):
Account Datekey Balance
1 20181012 100
1 20181112 100
1 20181212 100
1 20181312 100 Sat
1 20181412 100 Sun
1 20181512 100
1 20181612 100 PH
1 20181712 100
Also Datekey is numeric and not a date. I tried a couple solutions suggested but found that it simply duplicates the previous row multiple times without stopping when the next dates record is found. I need to run it as an update query that would execute daily on table A and add missing records when its executed (sometimes 2 or 3 days later).
Hope you can assist.
Thanks
This question has multiple parts:
Converting an obscene date format to a date
Generating "in-between" rows
Filling in the new rows with the previous value
Determining the day of the week
The following does most of this. I refuse to regenerate the datekey format. You really need to fix that.
This also assumes that your setting are for English week day names.
with t as (
select Account, Datekey, Balance, convert(date, left(dkey, 4) + right(dkey, 2) + substring(dkey, 5, 2)) as proper_date
from yourtable
),
dates as (
select account, min(proper_date) as dte, max(proper_date) as max_dte
from t
group by account
union all
select account, dateadd(day, 1, dte), max_dte
from dates
where dte < max_dte
)
select d.account, d.dte, t.balance,
(case when datename(weekday, d.dte) in ('Saturday', 'Sunday')
then left(datename(weekday, d.dte), 3)
else 'PH'
end) as indicator
from dates d cross apply
(select top (1) t.*
from t
where t.account = d.account and
t.proper_date <= d.dte
order by t.proper_date desc
) t
option (maxrecursion 0);

How to sum previous month values and current month values in SQL query

Please help me to solve this issue. I have to write a query to get the sum of previous month values and current month values but not able to get the solution.
Here is an image for your reference sum of actual count column values I need the result.
In Oracle you would use the following, could be not completely correct on the case statement:
Select
Site,
sum(value * (case (date_transaction > trunc(sysdate, 'MM') then 1 else 0 end))
volume_current_month
from myTable
where date_transaction between add_months(trunc(sysdate,'MM'),-1) and sysdate
group by site
The previous month is more or less the same using another case statement and ADD_MONTHS.
There are two ways to do this in Tableau :
First Way .
Under Analysis --> Total --> Add All SubTotals .
Second Way :
Create a calc field Total_event as :
WINDOW_SUM(SUM([Event Count]))
Compute the Window_sum as COMPUTE USING EVENT NAME .
If you CAN USE sql AND YOU actually need the previous month and not just all months summed by EventName then you could use LAG. I made the assumption that you are summing by EventName and you only want the current EventName and previous EventNAme
WITH Summed
AS
(
SELECT * ,
LAG(EventCount) OVER (Partition BY EventName ORDER BY trialmonth) as PrevEvent
FROM dbo.Table1
)
SELECT *,
SUM(PrevEvent+EventCount) AS SummedCount
FROM summed
GROUP BY Site
,TrialMonth
,EventName
,EventCount
, PrevEvent
This will produce output like this
Site TrialMonth EventName EventCount PrevEvent SummedCount
12101 2001-10-15 Actual Count 4 NULL NULL
12101 2001-10-15 Projected Count 8 NULL NULL
12101 2001-11-15 Actual Count 6 4 10
12101 2001-11-15 Projected Count 9 8 17
12101 2001-12-15 Actual Count 0 6 6
12101 2001-12-15 Projected Count 10 9 19
http://sqlfiddle.com/#!6/8253f0/2
In tableau -> Create a calculated field ->
// This is for previous month
if [date] >= DATE("01" +"-" + (Month(TODAY())-1) +"-" + YEAR(TODAY()))
and [date] <= DATE("31" +"-" + (Month(TODAY())-1) +"-" + YEAR(TODAY()))
//if the month has 30 or 28 days it will check that there is no 31 and return null
then
sum([Value])
end
//For current month ->
if Month([date]) = Month(TODAY()) then
sum([Value])
end
You will 2 fields returning previous month's sum and current month's sum, You can then use them as you wish.
On sql end you may use
For Previous Month ->
select sum(value) from table_name t where DATE_PART('month',t.date)=DATE_PART('month',TIMESTAMPADD(mm,-1,GETDATE()))
For current Month ->
select sum(value) from table_name t where DATE_PART('month',t.date)=DATE_PART('month',GETDATE()))

Last three months average for each month in PostgreSQL query

I'm trying to build a query in Postgresql that will be used for a budget.
I currently have a list of data that is grouped by month.
For each month of the year I need to retrieve the average monthly sales from the previous three months. For example, in January I would need the average monthly sales from October through December of the previous year. So the result will be something like:
1 12345.67
2 54321.56
3 242412.45
This is grouped by month number.
Here is a snippet of code from my query that will get me the current month's sales:
LEFT JOIN (SELECT SUM((sti.cost + sti.freight) * sti.case_qty * sti.release_qty)
AS trsf_cost,
DATE_PART('month', st.invoice_dt) as month
FROM stransitem sti,
stocktrans st
WHERE sti.invoice_no = st.invoice_no
AND st.invoice_dt >= date_trunc('year', current_date)
AND st.location_cd = 'SLC'
AND st.order_st != 'DEL'
GROUP BY month) as trsf_cogs ON trsf_cogs.month = totals.month
I need another join that will get me the same thing, only averaged from the previous 3 months, but I'm not sure how.
This will ALWAYS be a January-December (1-12) list, starting with January and ending with December.
This is a classic problem for a window function. Here is how to solve this:
SELECT month_nr
,(COALESCE(m1, 0)
+ COALESCE(m2, 0)
+ COALESCE(m3, 0))
/
NULLIF ( CASE WHEN m1 IS NULL THEN 0 ELSE 1 END
+ CASE WHEN m2 IS NULL THEN 0 ELSE 1 END
+ CASE WHEN m3 IS NULL THEN 0 ELSE 1 END, 0) AS avg_prev_3_months
-- or divide by 3 if 3 previous months are guaranteed or you don't care
FROM (
SELECT date_part('month', month) as month_nr
,lag(trsf_cost, 1) OVER w AS m1
,lag(trsf_cost, 2) OVER w AS m2
,lag(trsf_cost, 3) OVER w AS m3
FROM (
SELECT date_part( 'month', month) as trsf_cost -- some dummy nr. for demo
,month
FROM generate_series('2010-01-01 0:0'::timestamp
,'2012-01-01 0:0'::timestamp, '1 month') month
) x
WINDOW w AS (ORDER BY month)
) y;
This is requires that no month is ever missing! Else, have a look at this related answer:
How to compare the current row with next and previous row in PostgreSQL?
Calculates correct average for every month. If only two previous moths then devide by 2, etc. If no prev. months, result is NULL.
In your subquery, use
date_trunc('month', st.invoice_dt)::date AS month
instead of
DATE_PART('month', st.invoice_dt) as month
so you can sort months over the years easily!
More info
Window function lag()
date_trunc()

MySQL AVG function for recent 15 records by date (order date desc) in every symbol

I am trying to create a statement in SQL (for a table which holds stock symbols and price on specified date) with avg of 5 day price and avg of 15 days price for each symbol.
Table columns:
symbol
open
high
close
date
The average price is calculated from last 5 days and last 15 days. I tried this for getting 1 symbol:
SELECT avg(close),
avg(`trd_qty`)
FROM (SELECT *
FROM cashmarket
WHERE symbol = 'hdil'
ORDER BY `M_day` desc
LIMIT 0,15 ) s
but I couldn't get the desired list for showing avg values for all symbols.
You can either do it with row numbers as suggested by astander, or you can do it with dates.
This solution will also take the last 15 days if you don't have rows for every day while the row number solution takes the last 15 rows. You have to decide which one works better for you.
EDIT: Replaced AVG, use CASE to avoid division by 0 in case no records are found within the period.
SELECT
CASE WHEN SUM(c.is_5) > 0 THEN SUM( c.close * c.is_5 ) / SUM( c.is_5 )
ELSE 0 END AS close_5,
CASE WHEN SUM(c.is_5) > 0 THEN SUM( c.trd_qty * c.is_5 ) / SUM( c.is_5 )
ELSE 0 END AS trd_qty_5,
CASE WHEN SUM(c.is_15) > 0 THEN SUM( c.close * c.is_15 ) / SUM( c.is_15 )
ELSE 0 END AS close_15,
CASE WHEN SUM(c.is_15) > 0 THEN SUM( c.trd_qty * c.is_15 ) / SUM( c.is_15 )
ELSE 0 END AS trd_qty_15
FROM
(
SELECT
cashmarket.*,
IF( TO_DAYS(NOW()) - TO_DAYS(m_day) < 15, 1, 0) AS is_15,
IF( TO_DAYS(NOW()) - TO_DAYS(m_day) < 5, 1, 0) AS is_5
FROM cashmarket
) c
The query returns the averages of close and trd_qty for the last 5 and the last 15 days. Current date is included, so it's actually today plus the last 4 days (replace < by <= to get current day plus 5 days).
Use:
SELECT DISTINCT
t.symbol,
x.avg_5_close,
y.avg_15_close
FROM CASHMARKET t
LEFT JOIN (SELECT cm_5.symbol,
AVG(cm_5.close) 'avg_5_close',
AVG(cm_5.trd_qty) 'avg_5_qty'
FROM CASHMARKET cm_5
WHERE cm_5.m_date BETWEEN DATE_SUB(NOW(), INTERVAL 5 DAY) AND NOW()
GROUP BY cm_5.symbol) x ON x.symbol = t.symbol
LEFT JOIN (SELECT cm_15.symbol,
AVG(cm_15.close) 'avg_15_close',
AVG(cm_15.trd_qty) 'avg_15_qty'
FROM CASHMARKET cm_15
WHERE cm_15.m_date BETWEEN DATE_SUB(NOW(), INTERVAL 15 DAY) AND NOW()
GROUP BY cm_15.symbol) y ON y.symbol = t.symbol
I'm unclear on what trd_qty is, or how it factors into your equation considering it isn't in your list of columns.
If you want to be able to specify a date rather than the current time, replace the NOW() with #your_date, an applicable variable. And you can change the interval values to suit, in case they should really be 7 and 21.
Have a look at How to number rows in MySQL
You can create the row number per item for the date desc.
What you can do is to retrieve the Rows where the rownumber is between 1 and 15 and then apply the group by avg for the selected data you wish.
trdqty is the quantity traded on particular day.
the days are not in order coz the market operates only on weekdays and there are holidays too so date may not be continuous