SQL | Display all rows where date is not current month - sql

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()));

Related

Insert specific row of a table into same table ONCE only

I have a table containing the below elements:
YEAR | MONTH | COMP | COMP_DESC | FIRST_NAME | LAST_NAME | EMP_SD | CURR | METHOD | POSITION_STATUS
2021 | 2 | ABC | ABC Company | Jake | Sam | 11-01-2021 | USD | |
2021 | 5 | XYZ | XYZ Company | Neo | June | 23-09-2021 | USD | OPEN | METH_004
The Result i need:
YEAR | MONTH | COMP | COMP_DESC | FIRST_NAME | LAST_NAME | EMP_SD | CURR | METHOD | POSITION_STATUS
2021 | 2 | ABC | ABC Company | Jake | Sam | 11-01-2021 | USD | |
2021 | 5 | XYZ | XYZ Company | Neo | June | 23-09-2021 | USD | OPEN | METH_004
2021 | 5 | XYZ | XYZ Company | RP_Neo | RP_June | 24-09-2021 | USD | |
When POSITION_STATUS='METH_004' AND METHOD='OPEN', I need the specific row to be duplicated in the same table with change in date and change in name JUST ONCE. and when i re run the query i dont want any more duplication happening
Below is the Query i have written:
INSERT INTO Table1
(YEAR, MONTH, COMP, COMP_DESC, FIRST_NAME, LAST_NAME, EMP_SD, CURR)
SELECT T.YEAR, T.MONTH, T.COMP, T.COMP_DESC, CONCAT('RP_',FIRST_NAME) AS N1, CONCAT('RP_',LAST_NAME) AS N2,
EMP_DATE + INTERVAL '1 day' AS NXT_DAY, T.CURR FROM Table1 T WHERE POSITION_STATUS='OPEN' AND METHOD = 'METH_004'
EXCEPT
SELECT T1.POS, T1.YEAR, T1.MONTH, T1.COMP, T1.COMP_DESC, T1.COST_CENTER
FROM Table1 T1
INNER JOIN Table T2
ON T1.YEAR=T2.YEAR
AND T1.MONTH=T2.MONTH
AND T1.COMP=T2.COMP
AND T1.COMP_DESC=T2.COMP_DESC
AND T1.CURR=T2.CURR;
Can anyone suggest me changes to the code to get the result. The above code runs without error. But the row is not replicated.
Thanks

Postgresql: Calculate monthly running total with some months missing

I have a table like this:
| acct| month | total |
-------------------------------
| 123 | 02 | 100
| 123 | 03 | 100
| 123 | 04 | 100
| 123 | 06 | 100
| 123 | 07 | 100
I want to get a running total grouped by acct for each month. However as shown above the table does not have a record for month 5 (basically nothing changed in month 5), but I still want to create a row for month 5 that will be the same as the previous month 4 so that the result looks like:
| acct| month | total |
-------------------------------
| 123 | 02 | 100
| 123 | 03 | 200
| 123 | 04 | 300
| 123 | 05 | 300
| 123 | 06 | 400
| 123 | 07 | 500
Is there anyway to do this in Postgresql? I've explored using over and partition as described here Calculating Cumulative Sum in PostgreSQL but that is for the case where all months are present.
Assuming you really want a cumulative sum with missing months, use generate_series() to generate the dates and then left join and a cumulative sum:
select t.acct, gs.mon, sum(total) over (order by mon)
from generate_series(2, 7, 1) gs(mon) left join
t
on gs.mon = t.mon;

Filtering after a group by produces a different outcome than MySQL

I have the following table from which I try to extract all cust_id who have bought an item for the first time in January.
I found a way with MySQL but I'm working with Hive and it doesn't work
Consider this table:
| cust_id | created | year | month | item |
|---------|---------------------|------|-------|------|
| 100 | 2017-01-01 19:20:00 | 2017 | 01 | ABC |
| 100 | 2017-01-01 19:20:00 | 2017 | 01 | DEF |
| 100 | 2017-01-08 22:45:00 | 2017 | 01 | GHI |
| 100 | 2017-08-03 08:01:00 | 2017 | 08 | JKL |
| 100 | 2017-01-01 21:23:00 | 2017 | 01 | MNO |
| 130 | 2016-12-06 06:42:00 | 2016 | 12 | PQR |
| 140 | 2017-01-21 15:01:00 | 2017 | 01 | STU |
| 130 | 2017-01-29 13:20:00 | 2017 | 01 | VWX |
| 140 | 2017-04-10 09:15:00 | 2017 | 04 | YZZ |
With the following query, it works:
SELECT
cust_id,
year,
month,
MIN(STR_TO_DATE(created, '%Y-%m-%d %H:%i:%s')) AS min_date
FROM
t1
GROUP BY
cust_id
HAVING
year = '2017'
AND
month= '01'
And it returns this table:
| cust_id | year | month | min_date |
|---------|------|-------|---------------------|
| 100 | 2017 | 01 | 2017-01-01 19:20:00 |
| 140 | 2017 | 01 | 2017-01-21 15:01:00 |
But in Hive, I cannot filter the fields year and month with HAVING if they have not been grouped by previously. In other words, the previous query fails.
Instead, the following runs but don't produce the expected result:
SELECT
cust_id,
year,
month,
MIN(unix_timestamp(created, 'yyyy-MM-dd HH:mm:ss')) AS min_date
FROM
t1
GROUP BY
cust_id, year, month
HAVING
year = '2017'
AND
month= '01'
cust_id 130 shows up even if the first purchase happened in december 2016
| cust_id | year | month | min_date |
|---------|------|-------|---------------------|
| 100 | 2017 | 01 | 2017-01-01 19:20:00 |
| 130 | 2017 | 01 | 2017-01-29 13:20:00 |
| 140 | 2017 | 01 | 2017-01-21 15:01:00 |
Here is the fiddle : SQL fiddle
Thank you
Your MySQL query doesn't really work, even if it runs. Never have "bare" columns in the group by or having or order by (of an aggregation query). All non-aggregated columns should be the arguments to an aggregation function. In your case, year and month fall into this category.
What you appear to want in either database is something like this:
SELECT cust_id
FROM t1
GROUP BY cust_id
HAVING MIN(created) >= '2017-01-01' AND
MIN(created) < '2017-02-01';

How can I get average of groupings in a table and store the result back to the original table in SQL

I have the following table:
| Country | Month | Revenue |
|---------|-------|---------|
| US | Jan | 100 |
| US | Feb | 200 |
| US | Mar | 300 |
| Canada | Jan | 200 |
| Canada | Feb | 400 |
| Canada | Mar | 500 |
I need to get average revenue per country and store this value back to the original table to get the following output:
| Country | Month | Revenue | Average |
|---------|-------|---------|---------|
| US | Jan | 100 | 200 |
| US | Feb | 200 | 200 |
| US | Mar | 300 | 200 |
| Canada | Jan | 200 | 366.6 |
| Canada | Feb | 400 | 366.6 |
| Canada | Mar | 500 | 366.6 |
What is the best way to accomplish this in SQL? Is it better to use partition by?
The best way to do this uses window functions:
select t.*, avg(revenue) over (partition by country) as avg_revenue
from t;
To actually do the computation and store it back requires an update. Although there are other methods, the following is standard SQL:
update t
set average = (select avg(revenue) from t t2 where t.country = t2.country);
EDIT:
In T-SQL, you can somewhat improve the performance by doing:
with toupdate as (
select t.*,
avg(t.revenue) over (partition by t.country) as new_average
from t
)
update toupdate
set average = new_average;

Remove duplicate column value

Considering my table
+----+------+--------+----------+
| ID | Name | Salary | Month |
+----+------+--------+----------+
| 1 | a | 5000 | Jan |
| 2 | b | 5500 | Jan |
| 3 | b | 5300 | Feb |
| 4 | b | 5300 | Mar |
| 5 | b | 5300 | Apr |
| 6 | b | 5300 | May |
| 7 | b | 5300 | June |
| 8 | b | 5300 | July |
+----+------+--------+----------+
I need to display
+----+------+--------+----------+
| ID | Name | Salary | Month |
+----+------+--------+----------+
| 1 | a | 5000 | Jan |
| 2 | b | 5500 | Jan |
| 3 | | 5300 | Feb |
| 4 | | 5300 | Mar |
| 5 | | 5300 | Apr |
| 6 | | 5300 | May |
| 7 | | 5300 | June |
| 8 | | 5300 | July |
+----+------+--------+----------+
Can any1 help
I'm assuming the results are sorted by the name column (and probably then the salary?), you could use the analytic function ROW_NUMBER to single out the first one, and only print that one out.
You may want to tweak the query around a bit, but here's the main idea:
SELECT id, CASE rn WHEN 1 THEN name ELSE null END, salary, month
FROM (SELECT id, name, salary, month,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY salary) AS rn
FROM some_table)
ORDER BY name, rn
Please try below query for MS Sql server:
select
a.ID,
case when a.Name=b.Name then NULL else a.Name end Name,
a.Salary,
a.[Month]
from YourTable a left join YourTable b
on a.ID=b.ID+1