Postgresql transpose rows to columns - sql

I have this query
select * from sales
shop | date | hour | row_no | amount
-----------+------------+-----------+--------+-----------
shop_1 | 2012-08-14 | 00:08:00 | P01 | 10
shop_2 | 2012-08-12 | 00:12:00 | O05 | 40
shop_2 | 2012-08-12 | 00:12:00 | A01 | 20
I have 1 millon rows, I can do this query
select shop, SUM(amount)
from sales
group by shop
shop | amount |
-----------+------------+
shop_1 | 5666 |
shop_2 | 4044 |
shop_3 4044 |
But I need to spend the days at the columns and I do not know if they could help me do this
shop | 2012-08-1 | 2012-08-2 | 2012-08-3 |
-----------+------------+-----------+--------+-----------
shop_1 | 4005 | 5667 | 9987 |
shop_2 | 4333 | 4554 | 1234 |
shop_3 | 4555 | 6778 | 6677 |
Would be group by store in the rows, and group by days in the columns in postgresql

First, you must install tablefunc extension. Since version 9.1 you can do it using create extension:
CREATE EXTENSION tablefunc;
select * from crosstab (
select shop, date, SUM(amount)
from sales
group by shop
'select date from sales order by 1')
AS ct(shop: text, '2012-08-1' text, '2012-08-2' text, '2012-08-3' text)

Related

Group by sum with date and two different tables

The following extracts of two tables are given (Oracle SQL):
+----------+------------+-------------+
| Orders | | |
+----------+------------+-------------+
| Order ID | Date | Customer ID |
| 12345 | 12.05.2018 | 456 |
| 12346 | 01.09.2021 | 646 |
| 12347 | 03.03.2019 | 836 |
| 12348 | 04.06.2020 | 1026 |
| 12349 | 05.07.2020 | 1216 |
| 12350 | 04.01.2020 | 1406 |
+----------+------------+-------------+
+-------------+----------+
| Country | |
+-------------+----------+
| Customer ID | Country |
| 1026 | GB |
| 836 | USA |
| 1026 | Germany |
| 2166 | USA |
| 2546 | GB |
| 4154 | France |
+-------------+----------+
The desired outcome should provide lines with Order ID, Date, Customer ID, Country as well as:
The amount of orders by the customer of a certain order ID over the last 10 and 30 days
The amount of orders by the country of a certain customer over the last 10 and 30 days
Since every customer belongs to a country the aggregated amounty by country are always at least as high as by a customer.
So the result should look like this:
+--------------------------------------+------------+-------------+------------+-------------------------------------+-------------------------------------+------------------------------------+------------------------------------+
| Desired Outcome (Results fictitious) | | | | | | | |
+--------------------------------------+------------+-------------+------------+-------------------------------------+-------------------------------------+------------------------------------+------------------------------------+
| Order ID | Date | Customer ID | Country ID | Amount Orders Cutsomer Last 10 Days | Amount Orders Cutsomer Last 30 Days | Amount Orders Country Last 10 Days | Amount Orders Country Last 30 Days |
| 12347 | 03.03.2019 | 836 | USA | 7 | 15 | 124 | 578 |
+--------------------------------------+------------+-------------+------------+-------------------------------------+-------------------------------------+------------------------------------+------------------------------------+
Your requirements are not clearly stated but I think you are asking for a list of every order within last 30 days and a summary count by Customer and Country for within 10 and within 30 days.
In a CTE/SubQuery
Join the two table together using customer ID
add logical columns for order within 10 days, order within 30 days. These should return true = 1, false = 0
Select from CTE,
use
SUM(Within10) OVER(PARTITION BY CustomerID),
SUM(Within30) OVER(PARTITION BY CountryCode),
SUM(Within10) OVER(PARTITION BY CustomerID),
SUM(Within30) OVER(PARTITION BY CountryCode),
This is T-SQL so the syntax for PL/SQL may vary slightly

How to query table to get current total count including previous dates?

I want to get the current total count of registered users by the day in an SQL Database from this data:
| userID | date_registered |
| -------- | --------------- |
| 10012 | 2021-03-01 |
| 10043 | 2021-03-01 |
| 10065 | 2021-03-04 |
| 10087 | 2021-03-05 |
| 10091 | 2021-03-05 |
| 10123 | 2021-03-05 |
| 10231 | 2021-03-06 |
| 10421 | 2021-03-09 |
So for 2021-03-01, there are currently 2 registered users.
For 2021-03-04, there are currently 3 registered users (including registers from previous dates)
For 2021-03-05, there are currently 6 registered users (including registers from previous dates)
and so on...
So the expected result should be
| total_user | date |
| ---------- | --------------- |
| 2 | 2021-03-01 |
| 3 | 2021-03-04 |
| 6 | 2021-03-05 |
| 7 | 2021-03-06 |
| 8 | 2021-03-09 |
Is there an SQL query possible to accomplish this result in BigQuery?
Much appreciated the help.
In BigQuery or any reasonable database, we can aggregate by date and then use SUM as an analytic function:
SELECT
SUM(COUNT(*)) OVER (ORDER BY date_registered) AS total_user,
date_registered AS date
FROM yourTable
GROUP BY
date_registered
ORDER BY
date_registered;
Note that if the same user might be reported more than once on a given date, then use COUNT(DISTINCT userID) instead of COUNT(*).
You can use this, but there are more practical ways for mysql 8+
SELECT e1.date_registered, (SELECT COUNT(e2.userID) FROM example e2
WHERE e2.date_registered <= e1.date_registered) AS count_ FROM example e1
GROUP BY date_registered
SqlFiddle

SQL postgresql: maximum value and sum of values

I need to make a query to the following table, to return the maximum date grouped by code and also make the following calculation: deb-cre (maximum only).
How would I do this?
code | date | deb | cred
-----------------------------------
4 | 2018-01-01 | 100,00 | 200,00
4 | 2017-12-28 | 100,00 | 500,00
6 | 2018-01-23 | 350,00 | 400,00
6 | 2018-04-28 | 140,00 | 678,00
8 | 2018-01-12 | 156,00 | 256,00
8 | 2016-02-28 | 134,00 | 598,00
The result must be
4 | 2018-01-01 | -200,00
6 | 2018-04-28 | -50,00
8 | 2018-01-12 | -464,00
PostgreSQL's DISTINCT ON in combination with ORDER BY will return the first row per group:
SELECT DISTINCT ON (code)
code, date, deb - cre
FROM your_table
ORDER BY code, date DESC;

How to make projections with future dates using Redshift

I currently have a table called quantities with the following data:
+------+----------+----------+
| item | end_date | quantity |
+------+----------+----------+
| 1 | 26/11/17 | 100 |
+------+----------+----------+
| 2 | 28/11/17 | 300 |
+------+----------+----------+
| 3 | 30/11/17 | 500 |
+------+----------+----------+
I want to query it so I can get this result:
+--------+-------+
| date | total |
+--------+-------+
| 26-Nov | 900 |
+--------+-------+
| 27-Nov | 800 |
+--------+-------+
| 28-Nov | 800 |
+--------+-------+
| 29-Nov | 500 |
+--------+-------+
| 30-Nov | 500 |
+--------+-------+
How would this query look like? Many thanks!
Please note:
The above output is the result of suming the "quantity" field of each item when today's date is =< end_date. See below that today is the 26th of november.
+--------+-----+-----+-----+-------+
| date | 1 | 2 | 3 | total |
+--------+-----+-----+-----+-------+
| 26-Nov | 100 | 300 | 500 | 900 |
+--------+-----+-----+-----+-------+
| 27-Nov | - | 300 | 500 | 800 |
+--------+-----+-----+-----+-------+
| 28-Nov | - | 300 | 500 | 800 |
+--------+-----+-----+-----+-------+
| 29-Nov | - | - | 500 | 500 |
+--------+-----+-----+-----+-------+
| 30-Nov | - | - | 500 | 500 |
+--------+-----+-----+-----+-------+
I'd need the query to always give an output with the following date range:
start_date=current_date
end_date=the latest end_date from the list of items
I am using PostgreSQL 8.0.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3), Redshift 1.0.1499
t=# create table so (item serial, end_date date, quantity int);
CREATE TABLE
t=# set datestyle TO DMY;
SET
t=# insert into so(end_date,quantity) values('26-11-2017',100),('28-11-2017', 300), ('30-11-2017', 500);
INSERT 0 3
then, we create a view with a date series that goes into the future starting from today by using a table with a sequential id column:
CREATE VIEW future_dates AS
SELECT (getdate()::date -1 + id)::date as future_dates
FROM app_data.table_with_sequential_id
ORDER BY future_dates
N.b. We need to create the above view because generate_series is not fully supported in Redshift.
and lastly select itself:
t=# select gs::date, sum(quantity) over (order by gs desc rows unbounded preceding)
from future_dates gs
left outer join so on so.end_date = gs
order by gs ;
gs | sum
------------+-----
2017-11-26 | 900
2017-11-27 | 800
2017-11-28 | 800
2017-11-29 | 500
2017-11-30 | 500
(5 rows)

How to turn query result into another column that depends on different reference number but same year?

I have an Oracle table dummy which contains 3 columns reference_no, year and amount.
My question is how do compare each row and move the one that different to another column?
I have data like this
+--------------+-------+--------+
| REFERENCE_NO | YEAR | AMOUNT |
+--------------+-------+--------+
| A01 | 2010 | -100 |
| A01 | 2011 | -100 |
| A01 | 2012 | -100 |
| B02 | 2012 | -2000 |
| A01 | 2013 | -100 |
| B02 | 2013 | -2000 |
+--------------+-------+--------+
But the result I want is like this
+------+------------+------------+
| YEAR | AMOUNT A01 | AMOUNT B02 |
+------+------------+------------+
| 2010 | -100 | |
| 2011 | -100 | |
| 2012 | -100 | -2000 |
| 2013 | -100 | -2000 |
+------+------------+------------+
What is the best way to do this? It's like grouping by year and move the not same row to a new column.
http://sqlfiddle.com/#!4/b1c7f7/3
Sorry. My english is bad. Thanks
Self join
select a1.year, a1.amount as a01_amount, b2.amount as b02_amount
from dummy a1
left join dummy b2
on a1.year = b2.year
and b2.reference_no = 'B02'
where a1.reference_no = 'A01'
ORDER BY a1.year;
you would need to PIVOT the data as described here: https://www.techonthenet.com/oracle/pivot.php
SELECT * FROM
(
SELECT year, reference_no, amount
FROM dummy
)
PIVOT
(
SUM(amount)
FOR reference_no IN ('A01','B02' )
)
ORDER BY year;