I'm struggling with creating a temporary table with multiple conditions.
Let's call this main table A. I want to pull data from this table to output the distinct account with their last purchase date and payment date to a temporary table.
+---+--------+-----------+----------+
| | Acct | Trans_Date|Trans_code|
+---+--------+-----------+----------+
| 1 | ABC | July 31 | Purchase |
| 2 | ABC | Nov 5 | Payment |
| 3 | DEF | Mar 1 | Purchase |
| 4 | ABC | June 5 | Purchase |
| 5 | GFH | Feb 7 | Payment |
| 6 | GFH | Mar 9 | Purchase |
| 7 | DEF | Aug 8 | Payment |
| 8 | GFH | Mar 9 | Purchase |
| 9 | DEF | Aug 8 | Payment |
+---+--------+---------+----------+
Output result
+---+-------+----------------+--------------+
| | Acct | Last_trans_date|Last_transpay |
+---+-------+----------------+--------------+
| 1 | ABC | July 31 | Nov 5 |
| 2 | DEF | Mar 1 | Aug 8 |
| 3 | GFH | Mar 9 | Feb 7 |
+---+------+-----------------+--------------+
I read that using the WITH clauses could be an option, but struggling to understand it.
You can use conditional aggregation like so:
select acct,
max(case when trans_code = 'Purchase' then trans_date end) as last_purchase,
max(case when trans_code = 'Payment' then trans_date end) as last_payment
from mytable
group by acct
The syntax to insert the result of a query to another table varies across databases. In many of them, you can use:
create table newtable as
select ... -- above query
SQL Server is a notable exception, where you would need:
select ...
into newtable
from ...
group by ...
You can use conditional aggregation:
select acct, max(trans_date),
max(case when trans_code = 'Payment' then trans_date end)
from t
group by acct;
You can then insert this into an existing table or use the appropriate mechanism for your database to save the result as a new table.
Related
I am trying to get difference between total records and a column (Is_Registered) to get Month wise matrics of how many registered in particular month and how many are pending
Actual Data
| Inserted On | IsRegistered |
+-------------+--------------+
| 10-01-2020 | 1 |
| 15-01-2020 | 1 |
| 17-01-2020 | null |
| 17-02-2020 | 1 |
| 21-02-2020 | null |
| 04-04-2020 | null |
| 18-04-2020 | null |
| 19-04-2020 | 1 |
Expected Output -As shown in actual data, out of 8 users(records) 2 are registered in Jan and 6 are not ,in February total 3 are registered i.e. Jan's 2 + Feb's 1 and 5 are not and so on
| Year | Month | Registered | Not Registered |
| -------- | -------------- | ----------- | -------------- |
| 2020 | January | 2 | 6 |
| 2020 | Feb | 3 | 5 |
| 2020 | April | 4 | 4 |
But when a new record is added with new month then it should not update previous output result e.g. After adding new record with month as May and IsReg as NULL the value for Not_Registered should be as mentioned below because the new record is added in new month.
| Year | Month | Registered | Not Registered |
| -------- | -------------- | ----------- | -------------- |
| 2020 | January | 2 | 6 |
| 2020 | Feb | 3 | 5 |
| 2020 | April | 4 | 4 |
| 2020 | May | 4 | 5 |
And if the new record has month as May and Is_Registered as 1(true) then the output should be as follows
| Year | Month | Registered | Not Registered |
| -------- | -------------- | ----------- | -------------- |
| 2020 | January | 2 | 6 |
| 2020 | Feb | 3 | 5 |
| 2020 | April | 4 | 4 |
| 2020 | May | 5 | 4 |
I managed to write a query but didn't got expected output, what changes I'll have to make in order to get expected output
select year(dateinserted) as [Year], datename(month,dateinserted) as [Month],
coalesce(sum(cast(isregistered as int)), 0) as Authenticated,
sum(case when isregistered is null then 1 else 0 end) as UnAuthenticated
from table_name where IsRegistered is not null
group by year(dateinserted), datename(month,dateinserted)
order by year(dateinserted), month(min(dateinserted));
Output I got after executing above query -
| Year | Month | Registered | Not Registered |
| -------- | -------------- | ----------- | -------------- |
| 2020 | January | 2 | 1 |
| 2020 | Feb | 1 | 1 |
| 2020 | April | 1 | 2 |
Hmmm . . . You seem to want a cumulative sum of the counts (which are 1 or NULL, so count() works). For the second column, then difference between that and the total number of rows:
select year(dateinserted) as [Year],
datename(month, dateinserted) as [Month],
count(isregistered) as registered_in_month,
sum(count(isregistered)) over (order by min(dateinserted)) as registered_up_to_month,
sum(count(*)) over () - sum(count(isregistered)) over (order by min(dateinserted)) as not_yet_registered
from table_name
group by year(dateinserted), datename(month, dateinserted)
order by year(dateinserted), month(min(dateinserted));
Here is a db<>fiddle.
You should use self join and analytical function as follows:
Select year(t.inserted_on) as yr,
datename(month, t.dateinserted) as mnth,
Sum(count(t.is_registered))
over (order by min(t.inserted_on)) as resistered,
Tt.cnt - Sum(count(t.is_registered))
over (order by min(t.inserted_on)) as not_registered
From your_table t
Join (select t.*,
Count(*) over () as cnt
From your_table t) tt on t.inserted_on = tt.inserted_on
group by year(t.dateinserted), datename(month, t.dateinserted), tt.cnt
order by year(t.dateinserted), month(min(t.dateinserted));
This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 2 years ago.
I have a table looks like this
+----+------+------+-------+
| ID | FY | Code | Value |
+----+------+------+-------+
| 1 | 2021 | A | 2 |
+----+------+------+-------+
| 1 | 2021 | B | 5 |
+----+------+------+-------+
| 1 | 2021 | C | 3 |
+----+------+------+-------+
| 2 | 2021 | A | 4 |
+----+------+------+-------+
| 2 | 2021 | B | 5 |
+----+------+------+-------+
| 2 | 2021 | C | 6 |
+----+------+------+-------+
I want to expand the code column to the following format:
+----+------+---+---+---+
| ID | FY | A | B | C |
+----+------+---+---+---+
| 1 | 2021 | 2 | 5 | 3 |
+----+------+---+---+---+
| 2 | 2021 | 4 | 5 | 6 |
+----+------+---+---+---+
I came up with an ugly way as to use multiple Where sub query and join them together, but there are a few values in 'Code' column which make things ugly.
Is there an elegant way of achieving this? (SQL Server)
Best,
Use conditional aggregation:
select
id,
fy,
max(case when code = 'A' then value end) as A,
max(case when code = 'B' then value end) as B,
max(case when code = 'C' then value end) as C
from mytable
group by id, fy
I am currently working with a report through Microsoft Query and I ran into this problem where I need to calculate the total amount of money for the past year.
The table looks like this:
Item Number | Month | Year | Amount |
...........PAST YEARS DATA...........
12345 | 1 | 2019 | 10 |
12345 | 2 | 2019 | 20 |
12345 | 3 | 2019 | 15 |
12345 | 4 | 2019 | 12 |
12345 | 5 | 2019 | 11 |
12345 | 6 | 2019 | 12 |
12345 | 7 | 2019 | 12 |
12345 | 8 | 2019 | 10 |
12345 | 9 | 2019 | 10 |
12345 | 10 | 2019 | 10 |
12345 | 11 | 2019 | 10 |
12345 | 12 | 2019 | 10 |
12345 | 1 | 2020 | 10 |
12345 | 2 | 2020 | 10 |
How would you calculate the total amount from 02-2019 to 02-2020 for the item number 12345?
Assuming that you are running SQL Server, you can recreate a date with datefromparts() and use it for filtering:
select sum(amount)
from mytable
where
itemnumber = 12345
and datefromparts(year, month, 1) >= '20190201'
and datefromparts(year, month, 1) < '20200301'
You can use this also
SELECT sum(amount) as Amount
FROM YEARDATA
WHERE ( Month >=2 and year = '2019')
or ( Month <=2 and year = '2020')
and ItemNumber = '12345'
This question already has answers here:
SQL Server dynamic PIVOT query?
(9 answers)
Closed 3 years ago.
I would like to do a transposition to create columns from long list.
Here is the example
+-------+--------+--------+-------+
| id | typeid | type | value |
+-------+--------+--------+-------+
| a0001 | 01 | sales | 10 |
| a0001 | 02 | revune | 3 |
| a0001 | 03 | asset | 6 |
| a0002 | 01 | sales | 8 |
| a0002 | 03 | asset | 2 |
| a0003 | 01 | sales | 12 |
| a0003 | 02 | revune | 8 |
| a0003 | 03 | asset | 8 |
+-------+--------+--------+-------+
Since the value in type is enumerable, I would like to transform it into separate columns.
Here is the one I expected:
+-------+-------+---------+-------+
| id | sales | revenue | asset |
+-------+-------+---------+-------+
| a0001 | 10 | 3 | 6 |
| a0002 | 8 | null | 2 |
| a0003 | 12 | 8 | 8 |
+-------+-------+---------+-------+
I know how to do it in py/js.
I would like to know if it is possible to transpose using SQL in the database query?
If you know exactly which columns you want, you can use conditional aggregation:
select id,
sum(case when type = 'sales' then value end) as sales,
sum(case when type = 'revenue' then value end) as revenue,
sum(case when type = 'assets' then value end) as assets
from t
group by id;
If you want this to be flexible, then you need to construct the SQL as a string and execute it. That is called dynamic SQL and depends very much on the database you are using.
You could use conditional aggregation
select a.id
, sum(case when typeid='01' then value else 0 end) sales
, sum(case when typeid='02' then value else 0 end) revenue
, sum(case when typeid='03' then value else 0 end) asset
from my_table
group by id
I have a database where there are n products ,m units sold on different dates.
Like bags are sold on daily basis , some days 5 some days 6 etc.
Sample database :
+---------+----------+-------+
| Product | UnitSold | Date |
+---------+----------+-------+
| bag | 1 | 1 jun |
| wallet | 2 | 2 jun |
| purse | 3 | 3 jun |
| bag | 4 | 4 jun |
| shoes | 3 | 4 jun |
| Shirt | 2 | 1 jun |
| bag | 5 | 2 jun |
| shirt | 6 | 3 jun |
| Purse | 1 | 1 jun |
+---------+----------+-------+
I want a unique combination of results where a particular quantity of a product is sold on particular date. How can I do that?
Example I am looking for :
Result:
+---------+----------+-------+
| Product | UnitSold | Date |
+---------+----------+-------+
| bag | 1 | 1 jun |
| purse | 3 | 3 jun |
| shirt | 6 | 3 jun |
+---------+----------+-------+
Want a specific mapping of columns
How can I do that ? I am using Microsoft sql server 2008
You could throw in a rank or row number if you don't care about what result you really want.
I threw your data into a temp table and ran the following. It will give me one result per product. With rank, it will give me number 1 based on unit sold. You can change that if you want, based on date or whatever else.
select *
from (
select *,rank() over(partition by product order by unitsold ) as rnk
from #temp a
)final
where rnk = 1
product unitsold Date rnk
bag 1 2017-06-01 1
purse 3 2017-06-02 1
shirt 2 2017-06-02 1
shoes 3 2017-06-04 1
wallet 2 2017-06-02 1