I have a table with salary payments across departments ("Days from Y" = days since start of year, "Days to M" = days to end of month)
Department | Salary | Date | Type | Days from Y | Days to M
-----------+--------+------------+-----------------+-------------+-----------
Finance | 71 | 01-01-2016 | Regular payment | 1 | 30
Sales | 3000 | 20-01-2016 | Regular payment | 20 | 11
Sales | -300 | 21-01-2016 | Correction | 21 | 10
Finance | 2000 | 01-02-2016 | Regular payment | 32 | 27
Sales | 3100 | 15-02-2016 | Regular payment | 46 | 12
For regular payments, the salary needs to be corrected to present as if it was a full month. But, in the next month the correction of the previous month must not be included (because it's already provided for in the new salary) - only the correction of the last month should be included!
For Sales, that would be:
Date | Salary | Salary (cum.) | Correction | Salary (corr.) cum.
---------------------------------------------------------------------------
2016 | 5800 | 5800 | |
2016-01 | 2700 | 2700 | 1650 | 4350
2016-01-20 | 3000 | 3000 | 1650 | 4650
2016-01-21 | -300 | 2700 | | 4350
2016-02 | 2550 | 5250 | 2040 | 7290
2016-02-15 | 2550 | 5250 | 2040 | 7290
Calculating the correction itself is quite easy: if the it's a regular payment, then use that date to calculate the correction for the given month-department combination.
Using a LASTNONBLANK expression, I can make a correct cumulative measure that works for a single department:
Salary (corr.) cum := CACLULATE(MAX([Correction]); LASTNONBLANK([Date]; MAX([Correction])
However, this doesn't work across departments - for 2016-01 that would lead to wrong total counters:
Department | Salary | Salary (cum.) | Correction | measure | should be
-----------------------------------------------------------------------
(Total) | 2771 | 3071 | | 4721 | 6851
Finance | 71 | 71 | 2130 | 2201 | 2201
Sales | 2700 | 3000 | 1650 | 4650 | 4650
How do I create a measure that correctly calculates the corrections for each month, as well as gets the totals correct?
(so basically it looks to the last correction for each department (or other dimension) and uses the sum of these instead of the last correction across all dimensions)
You basically need to iterate over the departments.
Salary (corr.) cum :=
SUMX (
Departments,
CACLULATE(MAX([Correction]); LASTNONBLANK([Date]; MAX([Correction])
)
That should do the trick.
Alberto
Related
*I HAVE A QUESTION
You manage a pay application where members can transfer money to each other (one-to-one in each transaction). All transactions are recorded in the DB.
Write a SQL program (use the sql_and_logic_pay_app_ds.xlsx file) that shows which member has the most friends. please assist if my syntax is correct.
SELECT TO,
(COUNT(DISTINCT To) + COUNT(DISTINCT From)) as TotalFriends
FROM Sql_and_logic_pay_app_ds
GROUP BY TO
ORDER BY TotalFriends DESC
LIMIT 1
THIS IS THE TABLE
| FROM | TO | DATE | TOTAL |
| 12 | 34 | 13/09/2018 | 155 |
| 17 | 1 | 13/09/2018 | 334 |
| 12 | 20 | 13/09/2018 | 384 |
| 12 | 11 | 13/09/2018 | 994 |
| 20 | 8 | 13/09/2018 | 602 |
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
Given two tables, sales_reps and sales:
sales_reps
+--------+-------+
| rep_id | name |
+--------+-------+
| 1 | Tony |
+--------+-------+
| 2 | Jim |
+--------+-------+
| 3 | Laura |
+--------+-------+
| 4 | Sam |
+--------+-------+
sales
+------------+----------+--------+-------------+
| sale_date | sales_id | rep_id | sale_amount |
+------------+----------+--------+-------------+
| 2021-01-01 | 1 | 1 | 2000 |
+------------+----------+--------+-------------+
| 2021-01-01 | 2 | 1 | 4000 |
+------------+----------+--------+-------------+
| 2021-01-01 | 3 | 2 | 3000 |
+------------+----------+--------+-------------+
| 2021-01-01 | 4 | 1 | 1000 |
+------------+----------+--------+-------------+
| 2021-01-01 | 5 | 4 | 5000 |
+------------+----------+--------+-------------+
| 2021-01-02 | 6 | 3 | 10000 |
+------------+----------+--------+-------------+
| 2021-01-02 | 7 | 3 | 10000 |
+------------+----------+--------+-------------+
| 2021-01-02 | 8 | 2 | 4000 |
+------------+----------+--------+-------------+
| 2021-01-02 | 9 | 1 | 6000 |
+------------+----------+--------+-------------+
| 2021-01-02 | 10 | 4 | 2000 |
+------------+----------+--------+-------------+
| 2021-01-03 | 11 | 2 | 8000 |
+------------+----------+--------+-------------+
| 2021-01-03 | 12 | 2 | 1000 |
+------------+----------+--------+-------------+
| 2021-01-03 | 13 | 3 | 4500 |
+------------+----------+--------+-------------+
| 2021-01-03 | 14 | 3 | 4500 |
+------------+----------+--------+-------------+
I want to show how many unique reps made sales by date (easy) and the rep_id and name of the rep who generated the highest total sales amount for each date. If more than one rep generated the same greatest total sales amount for a date, I want to show the lesser rep_id and that rep's name. The results should look like this:
+------------+-------------+----------+----------+
| sale_date | unique_reps | best_rep | rep_name |
+------------+-------------+----------+----------+
| 2021-01-01 | 3 | 1 | Tony |
+------------+-------------+----------+----------+
| 2021-01-02 | 4 | 3 | Laura |
+------------+-------------+----------+----------+
| 2021-01-03 | 2 | 2 | Jim |
+------------+-------------+----------+----------+
Laura and Jim both generated $9,000 in sales on 2021-01-03. But Jim's rep_id is 2, which is less than Laura's rep_id of 3. So Jim is displayed as the rep who generated the greatest sales amount on 2021-01-03.
Postgres has a mode() function, but it doesn't allow you to choose which rep to choose in the case of ties. For that, you can be more explicit:
select distinct on (s.sale_date) s.sale_date,
s.rep_id, sr.name,
count(*) over (partition by s.date) as num_reps
from sales s join
sales_reps sr
on s.rep_id = sr.rep_id
group by s.sale_date, s.rep_id
order by s.sale_date, sum(s.sale_amount) desc, s.rep_id, sr.name;
What is this doing? It is aggregating by the date and sales rep. Because of the distinct on, though, it is only taking one row per date. In this row:
count(*) over (partition by date) counts the number of reps (it is counting the rows after the aggregation).
s.rep_id is chosen based on the order by criteria -- first the most sales, then by the lowest rep id.
sr.name is the name of the sales rep.
I have two tables
In one table there are my employees and when they changed the Department
In the second table there is my current date
Employee Table
+------------------+--------+-------------+-----------------+
| Personal Number | Salary | Department | MonthWhenJoined |
+------------------+--------+-------------+-----------------+
| 224 | 1000 | HR | 03 |
| 224 | 1500 | R&D | 07 |
| 578 | 1200 | Sales | 04 |
| 578 | 2000 | Engineering | 09 |
| 694 | 1400 | R&D | 04 |
| 694 | 1500 | Sales | 08 |
+------------------+--------+-------------+-----------------+
Table with current Date
+------------+-----+-------+------+
| Date | Day | Month | Year |
+------------+-----+-------+------+
| 01.09.2019 | 01 | 09 | 2019 |
+------------+-----+-------+------+
Now I want to only see all Employee that have no 'MonthWhenJoined' equal to the current Month.
So the Result would be something like this
+------------------+--------+-------------+-----------------+
| Personal Number | Salary | Departement | MonthWhenJoined |
+------------------+--------+-------------+-----------------+
| 224 | 1000 | HR | 03 |
| 224 | 1500 | R&D | 07 |
| 694 | 1400 | R&D | 04 |
| 694 | 1500 | Sales | 08 |
+------------------+--------+-------------+-----------------+
I know it can not be that hard, but I cant figure it out …
Thank you for your help!
in this case I would join two tables putting those dates as different on it
SELECT * FROM Employee
WHERE personalNumber NOT IN
(SELECT personalNumber
FROM Emplayee e
JOIN currentDate d ON e.MonthWhenJoined = d.month)
SELECT *
FROM Employee
WHERE PersonalNumber NOT IN (
SELECT PersonaNumber
FROM Employee
WHERE MonthWhenJoined =
SELECT Month
FROM currentDate
)
Simple,
SELECT
E.[Personal Number],
E.[Salary],
E.[Department],
E.[MonthWhenJoined]
FROM
[someSchema].[Employee] E
LEFT JOIN
[someSchema].[CurrentDate] C
ON C.[Month] = E.[MonthWhenJoined]
WHERE
C.[Date] IS NULL;
of course, there is no way to tell if that month was in the same year as the current date.
Simple:
SELECT * FROM employee WHERE `MonthWhenJoined` NOT IN(SELECT `Month` FROM date WHERE `Year` = YEAR(CURDATE()));
I'm trying to write an SQL report that groups rows, removes duplicates, and sums up values in virtual columns.
I have this table
make | model | warranty | price
-------+--------+----------+-------
Honda | Accord | 2 | 700
Honda | Civic | 3 | 500
Lexus | ES 350 | 1 | 900
Lexus | ES 350 | 1 | 900
Lexus | ES 350 | 2 | 1300
Lexus | ES 350 | 3 | 1800
(6 rows)
I'm trying to create a report that adds two virtual columns, qty and total. Total is the sum of qty * price. The table should like the one below.
qty | make | model | warranty | price | total
-------+--------+--------+----------+-------------
1 | Honda | Accord | 2 | 700 | 700
1 | Honda | Civic | 3 | 500 | 500
2 | Lexus | ES 350 | 1 | 900 | 1800
1 | Lexus | ES 350 | 2 | 1300 | 1300
1 | Lexus | ES 350 | 3 | 1800 | 1800
(5 rows)
I think this is simple aggregation:
select count(*) as qty, make, model, warranty,
avg(price) as price, sum(price) as total
from t
group by make, model, warranty;