SQL - How to check the status of salary incremented or decremented? - sql

I want to check if the salary has been increased or decreased. How can I do that?
A new column can be opened and written as ascending and descending.
I am using SQL Server.
Table:

Use a CTE (or a sub-query) with a LAG() to get each row's preceding wage value.
Then use a CASE expression to categorise the change.
WITH
data_lagged AS
(
SELECT
*,
LAG(wage) OVER (PARTITION BY CurrAccCode ORDER BY StartDate) AS wage_lag
FROM
yourTable
)
SELECT
*,
CASE WHEN wage > wage_lag THEN 'increase'
WHEN wage = wage_lag THEN 'no_change'
WHEN wage < wage_lag THEN 'decrease'
ELSE 'new_wage' END AS wage_change_mode
FROM
data_lagged

Related

SQL Group by balance

I have a table like below:
I want the results to be like below which fetch the start and end of the balance but we can't use group by as balance should be grouped only based on consecutive groups. can you please help me with this ?:
There is most certainly a duplicate of this question, however, it is easier to crank out an answer than to search. These types of problems, data in the order inserted or shown with no order indicator, can simply be solved by two derivative queries. The first to use LAG or LEAD to check for gaps and the second to sum up the changes which are represented by a value of 1 as opposed to 0. The key here, using MSSQL Server, is SUM(x) OVER (ORDER BY Date ROWS UNBOUNDED PRECEDING).
DECLARE #T TABLE(balance INT, date DATETIME)
INSERT #T VALUES
(36,'1/1/2020'),
(36,'1/2/2020'),
(36,'1/3/2020'),
(24,'1/4/2020'),
(24,'1/5/2020'),
(36,'1/6/2020'),
(36,'1/7/2020'),
(37,'1/8/2020'),
(38,'1/9/2020')
;WITH GapsMarked AS
(
--If the prev value by date (by natural order of data above) does not equal this value mark it as a boundry
SELECT *,
IsBoundry = CASE WHEN ISNULL(LAG(balance) OVER (ORDER BY date),balance) = balance THEN 0 ELSE 1 END
FROM #T
)
,VirtualGroup AS
(
SELECT
*,
--This serialzes the marked groups into seequntial clusters
IslandsMarked = SUM(IsBoundry) OVER (ORDER BY Date ROWS UNBOUNDED PRECEDING)
FROM
GapsMarked
)
SELECT
MAX(balance) AS balance,
MIN(date) AS start,
MAX(date) AS [end]
FROM
VirtualGroup
GROUP BY
IslandsMarked
select balance, min(start), max(end) from table where balance is in (
select balance from table
group by balance)
Hope it will help you

PostgreSQL fill out nulls with previous value by category

I am trying fill out some nulls where I just need them to be the previous available value for a name (sorted by date).
So, from this table:
I need the query to output this:
Now, the idea is that for Jane, on the second and third there was no score, so it should be equal to the previous date on which an score was available, for Jane. And the same for Jon. I am trying coalesce and range, but range is not implemented yet in Redshift. I also looked into other questions and they don't fully apply to different categories. Any alternatives?
Thanks!
select day, name,
coalesce(score, (select score
from [your table] as t
where t.name = [your table].name and t.date < [your table].date
order by date desc limit 1)) as score
from [your table]
The query straightforwardly implements the logic you described:
if score is not null, coalesce will return its value without executing the subquery
if score is null, the subquery will return the last available score for that name before the given date
It's a "gaps and islands" problem and a query can be like this
SELECT
day,
name,
MAX(score) OVER (PARTITION BY name, group_id) AS score
FROM (
SELECT
*,
SUM(CASE WHEN score IS NULL THEN 0 ELSE 1 END) OVER (PARTITION BY name ORDER BY day) AS group_id
FROM data
) groups
ORDER BY name DESC, day
You can check a working demo here

how to determine Maximum Month Year and Month

I have a table that stores salary information (SALARY with fields such as NATIONAL_ID, SALYEAR, SALMONTH, SALAMOUNT, DATE_PAID, etc) for employees.
I need to extract data from that table including the last month an employee was paid a salary.
Unfortunately, DATE_PAID column is null for many cases in that table which forces me to think of using a combination of SALYEAR, SALMONTH to determine the highest value.
SALMONTH stores numbers from 1-12 and SALYEAR stores year information i.e 2010, 2015, etc.
Using ROW_NUMBER, we can try:
WITH cte AS (
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY NATIONAL_ID
ORDER BY SALYEAR DESC, SALMONTH DESC) rn
FROM yourTable t
)
SELECT *
FROM cte
WHERE rn = 1;
The above approach will target the latest record for each NATIONAL_ID, with "latest" being defined as having the most recent month in the most recent year.
select max(to_date(sal_year||to_char(sal_month,'FM00'),'yyyymm'))
should do it. The TO_DATE is really just for completeness if you want a date datatype.
You would need to use COALESCE like this:
SELECT MAX(COALESCE(YEAR(DATE_PAID) * 100 + MONTH(DATE_PAID), SALYEAR * 100 + SALMONTH))
FROM tablename
Use Correlated Sub Query -
with temp as (
select national_id,
max(to_number(to_char(salyear)||lpad(to_char(salmonth),2,'0'))) as max_salmonthyear
from salary
group by national_id)
select *
from salary s, temp t
where s.national_id = t.national_id
and to_number(to_char(salyear)||lpad(to_char(salmonth),2,'0')) = t.max_salmonthyear
order by 1;
Why not just use aggregation?
select nationalid, max(salyear * 100 + salmonth) as salyearmonth
from t
group by nationalid;
If you want to convert the yearmonth to a date:
select nationalid,
to_date(max(salyear * 100 + salmonth), 'YYYYMM') as salyearmonth
from t
group by nationalid;
This returns the first date of the salary month.

How do I reset a sum() over () in a SQL Server query?

I have a derived table that looks like this example:
{select * from tb_data}
I want the results to have and additional summation column, the catch is I need the summation column to reset the working value if the info column value = 'reset'
{select *, (I assume some variation on sum(number) over (partition by id order by date desc)) as summation from tb_data}
and here's what the output should look like:
The actual derived table covers thousands of ids which is why it needs to be partitioned by the id and ordered by date desc and each has a different number of reset points.
What SQL query will get me the output I need?
You could first do a conditional window sum to define the groups: everytime a reset is found, a new group starts. Then you can simply do a window sum of numbers within the groups.
select
id,
date,
info,
number,
sum(number) over(partition by id, grp order by date) summation
from (
select
t.*,
sum(case when info = 'reset' then 1 else 0 end)
over(partition by id order by date) grp
from mytable t
) t

Rank Over Partition By in Oracle SQL (Oracle 11g)

I have 4 columns in a table
Company Part Number
Manufacturer Part Number
Order Number
Part Receipt Date
Ex.
I just want to return one record based on the maximum Part Receipt Date which would be the first row in the table (The one with Part Receipt date 03/31/2015).
I tried
RANK() OVER (PARTITION BY Company Part Number,Manufacturer Part Number
ORDER BY Part Receipt Date DESC,Order Number DESC) = 1
at the end of the WHERE statement and this did not work.
This would seem to do what you want:
select t.*
from (select t.*
from t
order by partreceiptdate desc
) t
where rownum = 1;
Analytic functions like rank() are available in the SELECT clause, they can't be invoked directly in a WHERE clause. To use rank() the way you want it, you must declare it in a subquery and then use it in the WHERE clause in the outer query. Something like this:
select company_part_number, manufacturer_part_number, order_number, part_receipt_date
from ( select t.*, rank() over (partition by... order by...) as rnk
from your_table t
)
where rnk = 1
Note also that you can't have a column name like company part number (with spaces in it) - at least not unless they are enclosed in double-quotes, which is a very poor practice, best avoided.