PowerQuery - How do I count events by dates spanning multiple years? - datetime

I would like to display activity counts by year e.g.
Year
Created
Approved
Resolved
2017
10
5
19
the source records look like this:
Record ID
Created Date
Approved Date
Resolved Date
123456
9/17/2017
1/15/2018
11/1/2019
Using the example record the report for 2017 should look like:
Year
Created
Approved
Resolved
2017
1
0
0
I've linked the source table to a Calendar using the record Created Date. When I try to count any other status but Created, however, I get the count of records based on when they were created, and not when the event occurred:
Year
Created
Approved
Resolved
2017
1
1
1
To count Date Resolved I've used: =calculate(count('source'[Resolved Date]),'calendar'[date]), which I know is incorrect. I want the count to be the number of items occurring during the year specified. Any help would be appreciated!

Sounds like you are looking for BI solution, but in case anyone ever needs a Powerquery/M solution
right click record_id and unpivot other columns
right click value column and tranform year...year
right click remove record_id column
add column, custom column, with formula =1
click attribute column and transform...pivot .. using the new custom column as value column
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Record ID", Int64.Type}, {"Created Date", type date}, {"Approved Date", type date}, {"Resolved Date", type date}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"Record ID"}, "Attribute", "Value"),
#"Extracted Year" = Table.TransformColumns(#"Unpivoted Other Columns",{{"Value", Date.Year, Int64.Type}}),
#"Removed Columns" = Table.RemoveColumns(#"Extracted Year",{"Record ID"}),
#"Added Custom" = Table.AddColumn(#"Removed Columns", "Custom", each 1),
#"Pivoted Column" = Table.Pivot(#"Added Custom", List.Distinct(#"Added Custom"[Attribute]), "Attribute", "Custom", List.Sum)
in #"Pivoted Column"

Related

Asp.net gridview Sorting by age

I have a table with column "Age", where sorted age is shown like:
10 years,
105 years
18 years,
60 years.
8 months.
How can I sort it not in alphabetical order, but in correct.
I can't eliminate word "years".
Well, if this is from say a database?
Then you could do this:
SELECT id, FirstName, LastName, Age,
cast(SUBSTRING(Age,1,Charindex(' ',Age)-1 ) as integer) as NumAge
FROM tblCustomers
ORDER BY NumAge
So, now you have a text display column, but you also have a real "number" column with the actual number in years - and you can sort correctly on that NumAge column. And this sort could also be done with a data-view sort - so however you were/are sorting the data, then sorting by NumAge will become a possible choice if you add the above column that plucks out the number from that column.
Now the Above works if we don't have a mix of month, and years. But, to handle that, then we change above to this:
SELECT id, FirstName, LastName, Age,
CASE
WHEN CharIndex('month',Age) > 0 THEN
(cast(SUBSTRING(Age,1,Charindex(' ',Age)-1 ) as integer))
WHEN CharIndex('year',Age) > 0 THEN
(cast(SUBSTRING(Age,1,Charindex(' ',Age)-1 ) * 12 as integer))
END
AS AgeInMonths
FROM tblCustomers
ORDER BY AgeInMonths
So, once again, we now have a number and value in months for age, and this can be sorted. So we display the Age + text column, but the sort expression can use AgeInMonths and the result is data in the correct order.
And if you have days? Then I would in place of the months * 12, using months * 30, and for year, then just use * 365. So, it not at all hard to have support for years, months, or days.
The result is once again, data sorted in number order by given age.
The problem is also "months". Is 8 months higher than 2 years or is 8 months 0 year?
If it is the last you can use Linq.
Lets say this are the ages.
var age = new List<string>()
{
"10 years,",
"105 years",
"18 years,",
"60 years.",
"8 months.",
"1 year.",
"18 months,",
};
Then you can do this. It splits the list in months and years. Then removes all characters except numbers. If it is a month divide it by 12 to get the years. Then sort it, and make it a string again and add "years" to it.
var sortedAge = age.Where(x => x.ToLower().Contains("month"))
.Select(x => Convert.ToInt32(string.Concat(x.Where(Char.IsDigit))) / 12)
.Concat(age.Where(x => x.ToLower().Contains("year"))
.Select(x => Convert.ToInt32(string.Concat(x.Where(Char.IsDigit)))))
.OrderBy(y => y)
.Select(z => z > 1 ? z.ToString() + " years" : z.ToString() + " year").ToList();
result
0 year
1 year
1 year
10 years
18 years
60 years
105 years
But you would still be better off just storing the age as an int in the DOB or even better, the date of birth as datetime.

Transpose rows to columns in SQLite

I have data like this:
I am trying to transform it to this (using SQLite). In the desired result, within each id, each start should be on the same row as the chronologically closest end. If an id has a start but no end (like id=4), then the corresponding end, will be empty (as shown below).
I have tried this
select
id,
max( case when start_end = "start" then date end) as start,
max(case when start_end = "end" then date end ) as end
from df
group by id
But the result is this, which is wrong because id=5 only have one row, when it should have two:
id start end
1 2 1994-05-01 1996-11-04
2 4 1979-07-18 <NA>
3 5 2010-10-01 2012-10-06
Any help is much appreciated
CREATE TABLE mytable(
id INTEGER NOT NULL PRIMARY KEY
,start_end VARCHAR(5) NOT NULL
,date DATE NOT NULL
);
INSERT INTO mytable(id,start_end,date) VALUES (2,'start','1994-05-01');
INSERT INTO mytable(id,start_end,date) VALUES (2,'end','1996-11-04');
INSERT INTO mytable(id,start_end,date) VALUES (4,'start','1979-07-18');
INSERT INTO mytable(id,start_end,date) VALUES (5,'start','2005-02-01');
INSERT INTO mytable(id,start_end,date) VALUES (5,'end','2009-09-17');
INSERT INTO mytable(id,start_end,date) VALUES (5,'start','2010-10-01');
INSERT INTO mytable(id,start_end,date) VALUES (5,'end','2012-10-06');
select
s.id as id,
s.date as 'start',
min(e.date) as 'end' -- earliest end date from "same id&start"
from
-- only start dates
(select id, date
from intable
where start_end='start'
) as s
left join -- keep the start-only lines
-- only end dates
(select id, date
from intable
where start_end='end'
) as e
on s.id = e.id
and s.date < e.date -- not too early
group by s.id, s.date -- "same id&start"
order by s.id, s.date; -- ensure sequence
Left join (to keep the start-only line for id "4") two on-the-fly tables, start dates and end dates.
Take the minimal end date which is just higher than start date (same id, using min()and group by.
Order by id, then start date.
I tested this on a test table which is similar to your dump, but has no "NOT NULL" and no "PRIMARY KEY". I guess for this test table that is irrelevant; otherwise explain the effect, please.
Note:
Internally three pairs of dates for id 5 (those that match end>start) are found, but only those are forwarded with the lowest end (min(end)) for each of the two different combinations of ID and start group by ID, start. The line where end>start but end not being the minimum is therefor not returned. That makes two lines with start/end pairs as desired.
Output (with .headers on):
id|start|end
2|1994-05-01|1996-11-04
4|1979-07-18|
5|2005-02-01|2009-09-17
5|2010-10-01|2012-10-06
UPDATE: Incorporate helpful comments by #MatBailie.
Thank you! This is exactly what I needed to do, only with a few changes:
SELECT
s.value AS 'url',
"AVGDATE" AS 'fieldname',
sum(e.value)/count(*) AS 'value'
FROM
(SELECT url, value
FROM quicktag
WHERE fieldname='NAME'
) AS s
LEFT JOIN
(SELECT url, substr(value,1,4) AS value
FROM quicktag
WHERE fieldname='DATE'
) AS e
ON s.url = e.url
WHERE e.value != ""
GROUP BY s.value;
I had a table like this:
url fieldname value
---------- ---------- ----------
1000052801 NAME Thomas
1000052801 DATE 2007
1000131579 NAME Morten
1000131579 DATE 2005
1000131929 NAME Tanja
1000131929 DATE 2014
1000158449 NAME Knud
1000158449 DATE 2007
1000158450 NAME Thomas
1000158450 DATE 2003
I needed to correlate NAME and DATE in columns based on url as a key, and generate a field with average DATE grouped by multiple NAME fields.
So my result looks like this:
url fieldname value
---------- ---------- ----------
Thomas AVGDATE 2005
Morten AVGDATE 2005
Tanja AVGDATE 2014
Knud AVGDATE 2007
Unfortunately I not have enough posts to make my vote count yet.

AgeCalendar Datetime Field Issue

For my AgingCalendar field, I have 3 conditions using CASE WHEN:
CASE WHEN A.[END_DTTM] > A.[STRT_DTTM] THEN C2.[DY_OF_CAL_NUM] - C1.[DY_OF_CAL_NUM]
WHEN A.[END_DTTM] IS NULL and A.[STRT_DTTM] IS NOT NULL THEN C3.[DY_OF_CAL_NUM] - C1.[DY_OF_CAL_NUM]
WHEN A.[END_DTTM] = A.[STRT_DTTM] THEN 1
END AS AgeCalendar
For my third condition, I'm trying to basically say when the End Datetime = Start Datetime, the age in Calendar days should be set to 1 calendar day.
However, in some of the records I'm bringing in, the start date equals the end date, but the times associated with each datetime are different. When this happens, those records are receiving a NULL in the AgeCalendar field.(For example I could have 6/6/2014 0:00:00 = 6/6/2014 0:00:00, and that will give me 1...but if I had 6/6/2014 0:00:00 = 6/6/2014 0:03:59 (or something like that)...it'll give me a NULL value because it's not matching.
How can I update the code above so that I'm basically saying when End Date = Start Date, then 1...regardless of not having matching times?
CASTor CONVERT them as dates to ignore the time.
WHEN CONVERT(DATE, A.[END_DTTM]) = CONVERT(DATE, A.[STRT_DTTM]) THEN 1
OR
WHEN CAST(A.[END_DTTM] AS DATE) = CAST(A.[STRT_DTTM] AS DATE) THEN 1

Shiny: BigQuery Fails when user selects "All" value

I am trying to use a BigQuery query to populate plots in Shiny. The query includes input values from the ui using selectInput. If the user selects a value that exists in the DB, such as year is 2014, the query works correctly, however, I would like the user to also be able to select "All." "All" should be a selection of all values, however, I am not sure how to express that in the query using selectInput.
server.r
data1 <- eventReactive(input$do_sql, {
bqr_auth(token = NULL, new_user = FALSE, verbose = FALSE)
query = paste('select month, event, partner_name, sum(f0_) from [dataset.table] where year =',input$year1,' and partner_name = \"',input$partner_name,'\"
GROUP by 1,2,3
ORDER by 1 asc
LIMIT 10000', sep="")
bqr_query(projectId, datasetId, query, maxResults =2000)
})
ui.r
(
selectInput("year1",
"Year:",
c("All",2014,2015
))
),
(
selectInput("partner_name",
"Partner:",
c("All",
unique(as.character(data5$partner_name))))
You should slightly change the query you are constructing
So, currently you have
SELECT month, event, partner_name, SUM(f0_)
FROM [dataset.table]
WHERE year = selected_year
AND partner_name = "selected_partner_name"
GROUP BY 1,2,3
ORDER BY 1 ASC
LIMIT 10000
with respectively:
selected_year --> input$year1
selected_partner_name --> input$partner_name
Instead, you should construct below query
SELECT month, event, partner_name, SUM(f0_)
FROM [dataset.table]
WHERE (year = selected_year OR "selected_year" = "All")
AND (partner_name = "selected_partner_name" OR "selected_partner_name" = "All")
GROUP BY 1,2,3
ORDER BY 1 ASC
LIMIT 10000
I am not shiny user at all - so excuse my syntax - below is just my
guess with regard of implementing above suggestion
query = paste('SELECT month, event, partner_name, sum(f0_)
FROM [dataset.table]
WHERE (year =',input$year1,' OR "All" ="',input$year1,'")
AND (partner_name = \"',input$partner_name,'\" OR "All" = \"',input$partner_name,'\")
GROUP by 1,2,3
ORDER by 1 asc
LIMIT 10000', sep="")
Mikhail's solution worked perfectly for character variables, but numerics didn't work correctly. I decided to use a character date range instead of the year numeric I originally used. Thanks.

How to find Sum of a field per month in a particular in sqlite3

I have a table created by the following statement in sqlite3
CREATE TABLE IF NOT EXISTS expenses
(
id INTEGER PRIMARY KEY,
name TEXT,
amount REAL,
category INT NOT NULL,
date TEXT
)
date entered in the database is in the format yyyy-mm-dd.
How to do i write a sqlite3 select statement such that i get sum of expenses per month in a given year. In other words if the user enters year 2011 I should get total expenses per month in 2011.
month total_amount
1 200
2 10
3 1500
4 340
5 124
SELECT SUM(amount) AS total_amount,
Strftime("%m", `date`) AS 'month'
FROM expenses
WHERE Strftime("%Y", `date`) = '2011'
GROUP BY Strftime("%m", `date`);
check out SQLite Date And Time Functions
(edited)

Resources