How to get Previous Value for Null Values - sql

I have the Below Data in my Table.
| Id | FeeModeId |Name | Amount|
---------------------------------------------
| 1 | NULL | NULL | 20 |
| 2 | 1 | Quarter-1 | 5000 |
| 3 | NULL | NULL | 2000 |
| 4 | 2 | Quarter-2 | 8000 |
| 5 | NULL | NULL | 5000 |
| 6 | NULL | NULL | 2000 |
| 7 | 3 | Quarter-3 | 6000 |
| 8 | NULL | NULL | 4000 |
How to write such query to get below output...
| Id | FeeModeId |Name | Amount|
---------------------------------------------
| 1 | NULL | NULL | 20 |
| 2 | 1 | Quarter-1 | 5000 |
| 3 | 1 | Quarter-1 | 2000 |
| 4 | 2 | Quarter-2 | 8000 |
| 5 | 2 | Quarter-2 | 5000 |
| 6 | 2 | Quarter-2 | 2000 |
| 7 | 3 | Quarter-3 | 6000 |
| 8 | 3 | Quarter-3 | 4000 |

Since you are on SQL Server 2012... here is a version that uses that. It might be faster than other solutions but you have to test that on your data.
sum() over() will do a running sum ordered by Id adding 1 when there are a value in the column and keeping the current value for null values. The calculated running sum is then used to partition the result in first_value() over(). The first value ordered by Id for each "group" of rows generated by the running sum has the value you want.
select T.Id,
first_value(T.FeeModeId)
over(partition by T.NF
order by T.Id
rows between unbounded preceding and current row) as FeeModeId,
first_value(T.Name)
over(partition by T.NS
order by T.Id
rows between unbounded preceding and current row) as Name,
T.Amount
from (
select Id,
FeeModeId,
Name,
Amount,
sum(case when FeeModeId is null then 0 else 1 end)
over(order by Id) as NF,
sum(case when Name is null then 0 else 1 end)
over(order by Id) as NS
from YourTable
) as T
SQL Fiddle
Something that will work pre SQL Server 2012:
select T1.Id,
T3.FeeModeId,
T2.Name,
T1.Amount
from YourTable as T1
outer apply (select top(1) Name
from YourTable as T2
where T1.Id >= T2.Id and
T2.Name is not null
order by T2.Id desc) as T2
outer apply (select top(1) FeeModeId
from YourTable as T3
where T1.Id >= T3.Id and
T3.FeeModeId is not null
order by T3.Id desc) as T3
SQL Fiddle

Please try:
select
a.ID,
ISNULL(a.FeeModeId, x.FeeModeId) FeeModeId,
ISNULL(a.Name, x.Name) Name,
a.Amount
from tbl a
outer apply
(select top 1 FeeModeId, Name
from tbl b
where b.ID<a.ID and
b.Amount is not null and
b.FeeModeId is not null and
a.FeeModeId is null order by ID desc)x
OR
select
ID,
ISNULL(FeeModeId, bFeeModeId) FeeModeId,
ISNULL(Name, bName) Name,
Amount
From(
select
a.ID , a.FeeModeId, a.Name, a.Amount,
b.ID bID, b.FeeModeId bFeeModeId, b.Name bName,
MAX(b.FeeModeId) over (partition by a.ID) mx
from tbl a left join tbl b on b.ID<a.ID
and b.FeeModeId is not null
)x
where bFeeModeId=mx or mx is null

SELECT
T.ID,
ISNULL(T.FeeModeId,
(SELECT TOP 1 FeeModeId
FROM TableName AS T1
WHERE ID < T.ID AND FeeModeId IS NOT NULL
ORDER BY ID DESC)) AS FeeModeId,
ISNULL(Name,
(SELECT TOP 1 Name
FROM TableName
WHERE ID < T.ID AND Name IS NOT NULL
ORDER BY ID DESC)) AS Name,
T.Amount
FROM
TableName AS T

try this -
SELECT Id,
CASE
WHEN Feemodeid IS NOT NULL THEN
Feemodeid
ELSE
(SELECT Feemodeid
FROM Table_Name t_2
WHERE t_2.Id = (SELECT MAX(Id)
FROM Table_Name t_3
WHERE t_3.Id < t_1.Id
AND Feemodeid IS NOT NULL))
END Feemodeid,
CASE
WHEN NAME IS NOT NULL THEN
NAME
ELSE
(SELECT NAME
FROM Table_Name t_2
WHERE t_2.Id = (SELECT MAX(Id)
FROM Table_Name t_3
WHERE t_3.Id < t_1.Id
AND NAME IS NOT NULL))
END NAME,
Amount
FROM Table_Name t_1

id name
1 toto
2 NULL
3 NULL
4 titi
5 NULL
6 NULL
7 tutu
8 NULL
9 NULL
SELECT
id_table
,name
FROM
(
SELECT
T_01.id AS 'id_table'
,max(T_02.id) AS 'id_name'
FROM
names AS T_01
cross join
(
SELECT
id
,name
FROM
names
WHERE
name IS NOT NULL
) AS T_02
WHERE
T_02.id <= T_01.id
GROUP BY
T_01.id
) AS tt02
left join names
ON names.id = tt02.id_name
id_table name
1 toto
2 toto
3 toto
4 titi
5 titi
6 titi
7 tutu
8 tutu
9 tutu

Related

Assign unique id based on combination in sql

The data looks like this:
Need to assign id based on the combination of 2 columns and get the id of each value in 2 columns
final output should look like:
I tried with
WITH RNS AS (
SELECT *, ROW_NUMBER() OVER () AS rn
FROM test
),
IDS AS (
SELECT t1.coLA, t1.colB, t1.rn, MIN(COALESCE(t2.rn, t1.rn)) AS id
FROM RNS t1
LEFT JOIN RNS t2 ON t1.rn > t2.rn
AND (t1.colA = t2.colA OR t1.colA = t2.colB OR
t1.colB = t2.colA OR t1.colB = t2.colB)
GROUP BY t1.coLA, t1.colB, t1.rn
ORDER BY t1.rn
)
SELECT colA, colB, DENSE_RANK() OVER (ORDER BY id) AS id
FROM IDS
ORDER BY rn
but not working as expected
Using RECURSIVE CTE in BigQuery, you may try below query
WITH RECURSIVE test AS (
SELECT * EXCEPT(offset)
FROM UNNEST(SPLIT('abaaeghjc', '')) colA WITH OFFSET
JOIN UNNEST(SPLIT('bccdfhikl', '')) colB WITH OFFSET USING (offset)
),
IDS AS (
SELECT *, DENSE_RANK() OVER (ORDER BY colA) id
FROM test t1
WHERE NOT EXISTS (SELECT 1 FROM test t2 WHERE t1.colA = t2.colB)
UNION ALL
SELECT t.*, id FROM IDS i JOIN test t ON i.colB = t.colA
)
SELECT DISTINCT col, id FROM IDS, UNNEST([colA, colB]) col
ORDER BY 1;
Query results:
+-----+----+
| col | id |
+-----+----+
| a | 1 |
| b | 1 |
| c | 1 |
| d | 1 |
| e | 2 |
| f | 2 |
| g | 3 |
| h | 3 |
| i | 3 |
| j | 4 |
| k | 4 |
| l | 1 |
+-----+----+

Insert into rows based on percentage

I have a table with employees. I need to populate the table with data based on 10 values from another table which contains 10 rows with columns ID and a name. I have to divide the employees in almost equal groups and add the IDs from the other table.
For example, 10% of employees should have first ID from the other table, other 10% of employees should have second ID from the same table etc.
Here is an example table of the employees
EmployeeID | Name | LevelID
----------------
1 | Name 1 | NULL
2 | Name 2 | NULL
3 | Name 3 | NULL
...
998 | Name 998 | NULL
999 | Name 999 | NULL
1000 | Name 1000 | NULL
Here is an example table of levels
LevelID | Level
----------------
1 | Level 1
2 | Level 2
3 | Level 3
...
8 | Level 8
9 | Level 9
10 | Level 10
I want my employee table to be updated like this:
EmployeeID | Name | LevelID
----------------
1 | Name 1 | 1
2 | Name 2 | 1
...
100 | Name 100 | 1
101 | Name 101 | 2
...
300 | Name 300 | 3
301 | Name 301 | 4
302 | Name 302 | 4
...
998 | Name 998 | 10
999 | Name 999 | 10
1000 | Name 1000 | 10
How can I achieve this in a query from SQL Server.
Kindly help me out.
Thanks
You can assign the values using window functions:
select t1.*, t2.*
from (select t1.*, ntile(10) over (order by (select null)) as tile
from table1 t1
) t1 join
(select t2.*, row_number() over (order by (select null)) as seqnum
from table2 t2
) t2
on t2.seqnum = t1.tile;
If you want to do this as an update:
with toupdate as (
select t1.*, ntile(10) over (order by (select null)) as tile
from table1 t1
)
update toupdate
set . . .
from toupdate join
(select t2.*, row_number() over (order by (select null)) as seqnum
from table2 t2
) t2
on t2.seqnum = toupdate.tile;

Select Except the duplicate Records from the table in SQL Server

I have a SQL Server table that has duplicate entries in one of the columns e.g.:
+----+-----------+------------+
| id | object_id | status_val |
+----+-----------+------------+
| 1 | 1 | 0 |
| 2 | 1 | 0 |
| 3 | 1 | 0 |
| 4 | 2 | 0 |
| 5 | 3 | 0 |
| 6 | 4 | 0 |
| 7 | 4 | 0 |
+----+-----------+------------+
I need the output to be like this:
+----+-----------+------------+
| id | object_id | status_val |
+----+-----------+------------+
| 4 | 2 | 0 |
| 5 | 3 | 0 |
+----+-----------+------------+
How to resolve this?
Is this what you are looking for?
SELECT * FROM <yourTable> t1
WHERE t1.object_id NOT IN
(
SELECT t2.object_id
FROM <yourTable> t2
GROUP BY t2.object_id
HAVING COUNT(object_id) > 1
)
Try this:
select min(id),
object_id,
min(status_val)
from table
group by object_id
having count(*) = 1
Use HAVING and GROUP BY
SELECT MIN(id) id, object_id, MIN(status_val) status_val
FROM yourtable
GROUP BY object_id
HAVING COUNT(object_id) = 1
Output
id object_id status_val
4 2 0
5 3 0
SQL Fiddle: http://sqlfiddle.com/#!6/7f643f/9/0
You can use group by for unique record like below :-
SELECT * from TABLENAME
group by TABLE_COLOUM_NAME
This query give you only unique value from your Table.
Give a row number for each row partitioned and ordered by the columns [object_id], [status_val]. Then from the result set select the rows which having maximum row number 1.
Query
;with cte as(
select [rn] = row_number() over(
partition by [object_id], [status_val]
order by [object_id], [status_val]
), *
from [your_table_name]
)
select min([id]) as [id], [object_id], [status_val]
from cte
group by [object_id], [status_val]
having max([rn]) = 1;
Find a demo here
SELECT COUNT(*)
FROM(
SELECT DISTINCT object_id
FROM object_table ) as row_count, status_val,id,object_id FROM object_table where row_count = 1;
I think you are looking for that

Add randomly selected column to result

I'd like to know if there is a more optimal query to get what I want from the database.
My database schema is as follows :
Table1:
(NUM_T1C1;ID_T1C2)
Table2:
(ID_T2C1;RES_T2C2)
First, I want to get a random row defined as:
SELECT NUM_T1C1, ID_T2C1
FROM (
SELECT T1.NUM_T1C1, T2.ID_T2C1, DBMS_RANDOM.VALUE
FROM TABLE1 T1, TABLE2 T2
WHERE T1.NUM_T1C1 IS NOT NULL
AND T2.RES_T2C2 IS NOT NULL
AND T1.ID_T1C2 = T2.ID_T2C1
ORDER BY 3
) WHERE ROWNUM = 1
I will call this query: QUERY1.
My question is as follows, I want to get a row as (random NUM_T1C1 != QUERY1.NUM_T1C1; ID_T2C1 == QUERY1.ID_T2C1), so I have tried:
SELECT NUM_T1C1, ID_T2C1
FROM (
SELECT R2.NUM_T1C1, R1.ID_T2C1, DBMS_RANDOM.VALUE
FROM (
SELECT NUM_T1C1, ID_T2C1
FROM (
SELECT T1.NUM_T1C1, T2.ID_T2C1, DBMS_RANDOM.VALUE
FROM TABLE1 T1, TABLE2 T2
WHERE T1.NUM_T1C1 IS NOT NULL
AND T2.RES_T2C2 IS NOT NULL
AND T1.ID_T1C2 = T2.ID_T2C1
ORDER BY 3
) WHERE ROWNUM = 1
) R1, TABLE1 R2
WHERE R2.NUM_T1C1 <> R1.NUM_T1C1
ORDER BY 3
) WHERE ROWNUM = 1
It's working, but I think this is not the optimal way to do so.
Is there a better way to get the expected result?
EDIT:
I found another way to get those random rows but i still don't know if it's optimal:
SELECT NUM_T1C1, ID_T2C1
FROM (
SELECT R1.NUM_T1C1, R2.ID_T2C1
FROM
(
SELECT T1.NUM_T1C1, T2.ID_T2C1, DBMS_RANDOM.VALUE
FROM TABLE1 T1, TABLE2 T2
WHERE T1.NUM_T1C1 IS NOT NULL
AND T2.T2C2 IS NULL
AND T1.ID_T1C2 = T2.ID_T2C1
ORDER BY 3
) R1,
(
SELECT T2.ID_T2C1, DBMS_RANDOM.VALUE
FROM TABLE1 T1, TABLE2 T2
WHERE T1.NUM_T1C1 IS NOT NULL
AND T2.T2C2 IS NOT NULL
AND T1.ID_T1C2 = T2.ID_T2C1
ORDER BY 2
) R2
) WHERE ROWNUM = 1
Here is an example :
Table1 Table2
+----------+---------+ +---------+----------+
| NUM_T1C1 | ID_T1C2 | | ID_T2C1 | RES_T2C2 |
+----------+---------+ +---------+----------+
| 23 | 5 | | 9 | NULL |
| 521 | 4 | | 4 | DG_513 |
| 71 | 7 | | 7 | FN_731 |
| 97 | 9 | | 5 | NULL |
+----------+---------+ +---------+----------+
Result would be one of those (select one randomly) :
+----------+---------+
| NUM_T1C1 | ID_T2C1 |
+----------+---------+
| 23 | 4 |
| 23 | 7 |
| 97 | 4 |
| 97 | 7 |
+----------+---------+
Here is one way with only a single (cross) join:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE Table1 ( NUM_T1C1, ID_T1C2 ) AS
SELECT 23, 5 FROM DUAL UNION ALL
SELECT 521, 4 FROM DUAL UNION ALL
SELECT 71, 7 FROM DUAL UNION ALL
SELECT 97, 9 FROM DUAL;
CREATE TABLE Table2 ( ID_T2C1, RES_T2C2 ) As
SELECT 9, NULL FROM DUAL UNION ALL
SELECT 4, 'DG_513' FROM DUAL UNION ALL
SELECT 7, 'FN_731' FROM DUAL UNION ALL
SELECT 5, NULL FROM DUAL;
Query 1:
SELECT NUM_T1C1, ID_T2C1
FROM (
SELECT NUM_T1C1,
ID_T2C1,
COUNT( CASE WHEN T1.ID_T1C2 = T2.ID_T2C1 THEN 1 END )
OVER ( PARTITION BY T1.NUM_T1C1 ) AS num_matches
FROM Table1 T1
CROSS JOIN
(
SELECT *
FROM Table2
WHERE RES_T2C2 IS NOT NULL
) T2
ORDER BY DBMS_RANDOM.VALUE
)
WHERE num_matches = 0
--AND ROWNUM = 1
Results:
| NUM_T1C1 | ID_T2C1 |
|----------|---------|
| 23 | 7 |
| 97 | 4 |
| 97 | 7 |
| 23 | 4 |

Get latest record from a subset in a Query

I have two related tables.
Table 1:
recordid | OrderNumber | MobileNumber
1 | 1234 | 9999999999
2 | 1234 | 9888888888
3 | 1234 | 9777777777
4 | 5433 | 9666666666
5 | 1444 | 9555555555
6 | 1444 | 9444444444
7 | 1544 | 9333333333
8 | 1632 | 9222222222
Table 2
recordid | modifiedon
1 | 15/1/2013
2 | 17/1/2013
3 | 13/1/2013
4 | 10/1/2013
5 | 16/1/2013
6 | 01/1/2013
7 | 09/1/2013
8 | 08/1/2013
what i want to do is get a unique set of OrderNumber and their corresponding MobileNumbers. If there is are more than one record for one OrderNumber, then the query should get OrderNumber and MobileNumber of the latest modified record.
So basically i should get the following result.
OrderNumber | MobileNumber
1234 | 9888888888
5433 | 9666666666
1444 | 9555555555
1544 | 9333333333
1632 | 9222222222
i have tried
select OrderNumber, MobileNumber from Table1
where OrderNumber in
(
Select Distinct table1. rderNumber, table2.ModifiedOn
from Table1, Table2
group by table2.ModifiedOn desc
)
This is urgent and I would be very greatly to receive quick responses.
It's easier with a CTE and ROW_NUMBER:
WITH cte AS
(SELECT t1.ordernumber,
t1.mobilenumber,
RN = Row_number()
OVER (
partition BY t1.ordernumber
ORDER BY t2, modifiedon DESC)
FROM table1 t1
INNER JOIN table2 t2
ON t1.recordid = t2.recordid)
SELECT ordernumber,
mobilenumber
FROM cte
WHERE rn = 1
Apart from that, you had a DESC after a GROUP BY.
select *
from
(
select t1.*,
row_number()
over (PARTITION BY t1.OrderNumber
ORDER BY t2.modifiedon DESC ) as rn
from t1
left join t2 on (t1.recordid=t2.recordid)
)
where RN=1