Convert Access Crosstab Query to T-SQL Equivalent - tsql

TRANSFORM Count(qryEAOCalls.CALLID) AS CountOfCALLID
SELECT qryEAOCalls.TAPSTAFFNAME, Count(qryEAOCalls.CALLID) AS [Total Calls]
FROM qryEAOCalls
WHERE qryEAOCalls.CALLDATE Between #1/1/1900# And Date()
GROUP BY qryEAOCalls.TAPSTAFFNAME
PIVOT qryEAOCalls.Status In ("Unassigned","Open","Closed","Follow-up Needed");
How do I convert this to T-SQL equivalent?

You should be able to use something similar to the following:
select TAPSTAFFNAME,
Unassigned, Open, Closed, [Follow-up Needed],
TotalCalls
from
(
select e.TAPSTAFFNAME,
e.CALLID,
e.Status,
count(*) over(partition by e.TAPSTAFFNAME) TotalCalls
from qryEAOCalls e
where e.CALLDATE >= '1900-01-01'
and e.CALLDATE <= getdate()
) src
pivot
(
count(CALLID)
for status in (Unassigned, Open, Closed, [Follow-up Needed])
) piv

Related

PostgreSQL: How to truncate and group timestamps?

I am working with a database and am using the following query:
SELECT
evt_block_time,
COUNT(*) filter (
WHERE
uniswap_version = 'v1'
) OVER (
ORDER BY
evt_block_time
) as v1_pairs,
COUNT(*) filter (
WHERE
uniswap_version = 'v2'
) OVER (
ORDER BY
evt_block_time
) as v2_pairs
FROM
(
SELECT
'v2' as uniswap_version,
evt_block_time
FROM
uniswap_v2."Factory_evt_PairCreated"
UNION ALL
SELECT
'v1' as uniswap_version,
evt_block_time
FROM
uniswap."Factory_evt_NewExchange"
ORDER BY
evt_block_time
) as creations
Here's a glimpse at what it returns:
I would like to do a few things. First of all, truncate the timestamps, evt_block_time, by week and then group by week.
NOTE: I tried using date_trunc('week', evt_block_time) under each of my select statements, but it throws an error. See below:
SELECT
date_trunc('week', evt_block_time),
COUNT(*) filter (
WHERE
uniswap_version = 'v1'
) OVER (
ORDER BY
evt_block_time
) as v1_pairs,
COUNT(*) filter (
WHERE
uniswap_version = 'v2'
) OVER (
ORDER BY
evt_block_time
) as v2_pairs
FROM
(
SELECT
'v2' as uniswap_version,
date_trunc('week', evt_block_time)
FROM
uniswap_v2."Factory_evt_PairCreated"
UNION ALL
SELECT
'v1' as uniswap_version,
date_trunc('week', evt_block_time)
FROM
uniswap."Factory_evt_NewExchange"
ORDER BY
evt_block_time
) as creations
which returns:
Column "evt_block_time" does not exist at line 31, position 26.
Additionally, though I guess it's not required, I would like to only query data from the last 52 weeks (1 year).
Obviously, I'm kinda new to this SQL thing but I'm trying my best. Any help whatsoever would be appreciated!
The problem is you're selecting evt_block_time from the subquery, but the subquery no longer contains evt_block_time, it contains date_trunc('week', evt_block_time).
To fix this, give it a name like evt_block_week and select that.
Since it's a calculated column you can't order by it, but the order by in the subquery does nothing. Remove it. If you want to apply an order, do it in surrounding query.
The orders in the count filters also do nothing, order doesn't matter for a count. Remove them.
Finally, to get the number of each version of timestamp per week, group by evt_block_week. And also order by evt_block_week.
SELECT
evt_block_week,
COUNT(*) filter (
WHERE
uniswap_version = 'v1'
) as v1_pairs,
COUNT(*) filter (
WHERE
uniswap_version = 'v2'
) as v2_pairs
FROM
(
SELECT
'v2' as uniswap_version,
date_trunc('week', evt_block_time) as evt_block_week
FROM
uniswap_v2."Factory_evt_PairCreated"
UNION ALL
SELECT
'v1' as uniswap_version,
date_trunc('week', evt_block_time) as evt_block_week
FROM
uniswap."Factory_evt_NewExchange"
) as creations
group by evt_block_week
order by evt_block_week
If you want to only do a range of weeks, use generate_series to generate a list of weeks. If you want to see all weeks, use that as the from sub-query and left join with creations. Order and group by the generated week.
SELECT
weeks.week,
COUNT(*) filter (
WHERE
uniswap_version = 'v1'
) as v1_pairs,
COUNT(*) filter (
WHERE
uniswap_version = 'v2'
) as v2_pairs
from (
select
generate_series(
date_trunc('week', '2020-01-01'::date), date_trunc('week', '2020-12-31'::date), '1 week'
) as week
) as weeks
left join
(
SELECT
'v2' as uniswap_version,
date_trunc('week', evt_block_time) as evt_block_week
FROM
uniswap_v2."Factory_evt_PairCreated"
UNION ALL
SELECT
'v1' as uniswap_version,
date_trunc('week', evt_block_time) as evt_block_week
FROM
uniswap."Factory_evt_NewExchange"
) as creations on weeks.week = evt_block_week
group by week
order by week
Demonstration.
Your subquery creations does not have a column with alias evt_block_time, consequently you cannot use that column name in the main query.

Using min/max values from a CTE in a later query, instead of using a subquery in Postgres

I've got a remedial question about pulling results out of a CTE in a later part of the query. For the example code, below are the relevant, stripped down tables:
CREATE TABLE print_job (
created_dts timestamp not null default now(),
status text not null
);
CREATE TABLE calendar_day (
date_actual date not null
);
In the current setup, there are gaps in the dates in the print_job data, and we would like to have a gapless result. For example, there are 87 days from the first to last date in the table, and only 77 days in there have data. We've already got a calendar_day dimension table to join with to get the 87 rows for the 87-day range. It's easy enough to figure out the min and max dates in the data with a subquery or in a CTE, but I don't know how to use those values from a CTE. I've got a full query below, but here are the relevant fragments with comments:
-- Get the date range from the data.
date_range AS (
select min(created_dts::date) AS start_date,
max(created_dts::date) AS end_date
from print_job),
-- This CTE does not work because it doesn't know what date_range is.
complete_date_series_using_cte AS (
select actual_date
from calendar_day
where actual_date >= date_range.start_date
and actual_date <= date_range.end_date
),
-- Subqueries are fine, because the FROM is specified in the subquery condition directly.
complete_date_series_using_subquery AS (
select date_actual
from calendar_day
where date_actual >= (select min(created_dts::date) from print_job)
and date_actual <= (select max(created_dts::date) from print_job)
)
I run into this regularly, and finally figured I'd ask. I've hunted around already for an answer, but I'm not clear how to summarize it well. And while there's nothing wrong with the subqueries in this case, I've got other situations where a CTE is nicer/more readable.
If it helps, I've listed the complete query below.
-- Get some counts and give them names.
WITH
daily_status AS (
select created_dts::date as created_date,
count(*) AS daily_total,
count(*) FILTER (where status = 'Error') AS status_error,
count(*) FILTER (where status = 'Processing') AS status_processing,
count(*) FILTER (where status = 'Aborted') AS status_aborted,
count(*) FILTER (where status = 'Done') AS status_done
from print_job
group by created_dts::date
),
-- Get the date range from the data.
date_range AS (
select min(created_dts::date) AS start_date,
max(created_dts::date) AS end_date
from print_job),
-- There are gaps in the data, and we want a row for dates with no results.
-- Could use generate_series on a timestamp & convert that to dates. But,
-- in our case, we've already got dimension tables for days. All that's needed
-- here is the actual date.
-- This CTE does not work because it doesn't know what date_range is.
-- complete_date_series_using_cte AS (
-- select actual_date
--
-- from calendar_day
--
-- where actual_date >= date_range.start_date
-- and actual_date <= date_range.end_date
-- ),
complete_date_series_using_subquery AS (
select date_actual
from calendar_day
where date_actual >= (select min(created_dts::date) from print_job)
and date_actual <= (select max(created_dts::date) from print_job)
)
-- The final query joins the complete date series with whatever data is in the print_job table daily summaries.
select date_actual,
coalesce(daily_total,0) AS total,
coalesce(status_error,0) AS errors,
coalesce(status_processing,0) AS processing,
coalesce(status_aborted,0) AS aborted,
coalesce(status_done,0) AS done
from complete_date_series_using_subquery
left join daily_status
on daily_status.created_date =
complete_date_series_using_subquery.date_actual
order by date_actual
I said it was a remedial question....I remembered where I'd seen this done before:
https://tapoueh.org/manual-post/2014/02/postgresql-histogram/
In my example, I need to list the CTE in the table list. That's obvious in retrospect, and I realize that I automatically don't think to do that as I'm habitually avoiding CROSS JOIN. The fragment below shows the slight change needed:
WITH
date_range AS (
select min(created_dts)::date as start_date,
max(created_dts)::date as end_date
from print_job
),
complete_date_series AS (
select date_actual
from calendar_day, date_range
where date_actual >= date_range.start_date
and date_actual <= date_range.end_date
),

How to translate SQL to DAX, Need to add FILTER

I want to create calculated table that will summarize In_Force Premium from existing table fact_Premium.
How can I filter the result by saying:
TODAY() has to be between `fact_Premium[EffectiveDate]` and (SELECT TOP 1 fact_Premium[ExpirationDate] ORDE BY QuoteID DESC)
In SQL I'd do that like this:
`WHERE CONVERT(date, getdate()) between CONVERT(date, tblQuotes.EffectiveDate)
and (
select top 1 q2.ExpirationDate
from Table2 Q2
where q2.ControlNo = Table1.controlno
order by quoteid` desc
)
Here is my DAX statement so far:
In_Force Premium =
FILTER(
ADDCOLUMNS(
SUMMARIZE(
//Grouping necessary columns
fact_Premium,
fact_Premium[QuoteID],
fact_Premium[Division],
fact_Premium[Office],
dim_Company[CompanyGUID],
fact_Premium[LineGUID],
fact_Premium[ProducerGUID],
fact_Premium[StateID],
fact_Premium[ExpirationDate]
),
"Premium", CALCULATE(
SUM(fact_Premium[Premium])
),
"ControlNo", CALCULATE(
DISTINCTCOUNT(fact_Premium[ControlNo])
)
), // Here I need to make sure TODAY() falls between fact_Premium[EffectiveDate] and (SELECT TOP 1 fact_Premium[ExpirationDate] ORDE BY QuoteID DESC)
)
Also, what would be more efficient way, to create calculated table from fact_Premium or create same table using sql statement (--> Get Data--> SQL Server) ?
There are 2 potential ways in T-SQL to get the next effective date. One is to use LEAD() and another is to use an APPLY operator. As there are few facts to work with here are samples:
select *
from (
select *
, lead(EffectiveDate) over(partition by CompanyGUID order by quoteid desc) as NextEffectiveDate
from Table1
join Table2 on ...
) d
or
select table1.*, oa.NextEffectiveDate
from Table1
outer apply (
select top(1) q2.ExpirationDate AS NextEffectiveDate
from Table2 Q2
where q2.ControlNo = Table1.controlno
order by quoteid desc
) oa
nb. an outer apply is a little similar to a left join in that it will allow rows with a NULL to be returned by the query, if that is not needed than use cross apply instead.
In both these approaches you may refer to NextEffectiveDate in a final where clause, but I would prefer to avoid using the convert function if that is feasible (this depends on the data).

Select not null column in full join postgresql

I have 3 tables:
with current_exclusive as(
select id_station, area_type,
count(*) as total_entries
from c1169.data_cashier
where id_station IN(2439,2441,2443,2445,2447,2449) and date >= '2017-10-30' and date <= '2017-12-30'
group by id_station, area_type
), current_table as(
select id_station, area_type,
sum(total_time) filter (where previous_status = 1) as total_time
from c1169.data_table
where id_station IN(2439,2441,2443,2445,2447,2449) and date >= '2017-10-30' and date < '2017-12-30'
group by id_station, area_type
), current_cashier as(
select id_station, area_type,
sum(1) as total_transactions
from c1169.data_cashier
where id_station IN(2439,2441,2443,2445,2447,2449) and date >= '2017-10-30' and date < '2017-12-30'
group by id_station, area_type
)
select *
from current_exclusive
full join current_table on current_exclusive.id_station = current_table.id_station and current_exclusive.area_type = current_table.area_type
full join current_cashier on current_exclusive.id_station = current_cashier.id_station and current_exclusive.area_type = current_cashier.area_type
and the result is:
but my expected result is:
Are there any way to select * and show the expected result? Because when I do full join then id_station and area_type can be null in some tables, so it very hard to choose which column is not null.
Like: select case id_station is not null then id_station else id_station1 end, but I have up to 10 tables so can not do in select case
Use USING, per the documentation:
USING ( join_column [, ...] )
A clause of the form USING ( a, b, ... ) is shorthand for ON left_table.a = right_table.a AND left_table.b = right_table.b .... Also, USING implies that only one of each pair of equivalent columns will be included in the join output, not both.
select *
from current_exclusive
full join current_table using (id_station, area_type)
full join current_cashier using (id_station, area_type)
You cannot accomplish anything if you insist on using select *, since you are getting the values from different tables.
The option you have is to include a COALESCE block which gives you the first non-null value from the list of columns.
So, you could use.
select COALESCE( current_exclusive.id_station, current_table.id_station, current_cashier.id_station ) as id_station ,
COALESCE( current_exclusive.area_type , current_table.area_type, current_cashier.area_type ) as area_type ,.....
...
from current_exclusive
full join current_table..
...

counting all occurrences in the last year

I have a question, although I can't really go into specifics.
Will the following query:
SELECT DISTINCT tableOuter.Property, (SELECT COUNT(ID) FROM table AS tableInner WHERE tableInner.Property = tableOuter.Property)
FROM table AS tableOuter
WHERE tableOuter.DateTime > DATEADD(year, -1, GETDATE())
AND tableOuter.Property IN (
...
)
Select one instance of each property in the IN clause, together with how often a row with that property occured in the last year?
I just read up on Correlated Subqueries on MSDN, but am not sure if I got it right.
If i understand you corrrecly, you want to get all occurences of each Property in the last year, am i right?
Then use GROUP BY with a HAVING clause:
SELECT tableOuter.Property, COUNT(*) AS Count
FROM table AS tableOuter
GROUP BY tableOuter.Property
HAVING tableOuter.DateTime > DATEADD(year, -1, GETDATE())
AND tableOuter.Property IN ( .... )