Update based on previous value SQL SERVER 2005 - sql

I need to Update these NULL Values:
PK | CODE
---+-------
1 | 20
2 | NULL
3 | NULL
4 | 30
5 | NULL
6 | NULL
7 | NULL
8 | 40
9 | NULL
Like this:
PK | CODE
-----+------------
1 | 20
2 | 20
3 | 20
4 | 30
5 | 30
6 | 30
7 | 30
8 | 40
9 | 40
It should always be based on the last minimum value.
I have tried the code below, but it just updates the first row before the one who had value at the beginning.
QUERY
UPDATE TT
SET CODE = (SELECT CODE
FROM #TSPV_TEMP T2 with(nolock)
WHERE T2.KEY = (tt.KEY -1))
FROM #TSPV_TEMP TT with (nolock)
WHERE tt.CODE IS NULL

You can do this as:
UPDATE TT
SET CODE = (SELECT TOP 1 CODE
FROM #TSPV_TEMP T2 with(nolock)
WHERE T2.KEY < tt.KEY AND
CODE IS NOT NULL
ORDER BY KEY DESC
)
FROM #TSPV_TEMP TT with (nolock)
where tt.CODE IS NULL;
Note the differences in the subquery. This looks for the previous non-NULL value for CODE for the update.

update tbl
set code =
(select code
from tbl x
where x.pk = (select max(y.pk)
from tbl y
where y.pk < tbl.pk
and code is not null))
where code is null;
Fiddle:
http://sqlfiddle.com/#!3/3803d/1/0

Another way using a derived table which for every pk with a null code contains the maximum lesser pk with a non-null code.
update t1
set t1.code = t3.code
from tt t1 join
(select t1.pk, max(t2.pk) max_pk
from tt t1
join tt t2 on t1.pk > t2.pk
and t2.code is not null
and t1.code is null
group by t1.pk) t2 on t2.pk = t1.pk
join tt t3 on t3.pk = t2.max_pk

Related

Join tables with same keys, second table has multiple values for key and rows of second table must have same column value

I have two tables with shared key and I'm trying to join them to filter data based on few conditions
tbl1
id | OutPutValue |
1 | 2019 |
2 | 2018 |
tbl2
object_id | status | type |
1 | 22 | a |
1 | 22 | c |
1 | 33 | b |
2 | 33 | c |
2 | 33 | c |
2 | 33 | c |
What I'm trying to get is : it must select all 'OutPutValue' from tbl1 where, in tbl2 column 'type' should be c, and column 'status' must have same value for all rows i.e. 33. Note that Primary key (id) of tbl1 is foreign key (object_id) in tbl2.
Select column from tbl1 if, All rows in tbl2 (id of tbl1 have multiple rows (based on object_id) in tbl2) have same status value i.e. 33 and Type should be 'c'.
OutPutValue | Type | status |
2018 | c | 33 |
I have tried with following solution, but it's not returning desired output :
SELECT a.OutPutValue FROM tbl1 a JOIN tbl2 b ON a.id = b.object_id WHERE b.Type =c
GROUP BY a.OutPutValue, b.status HAVING b.STATUS IN(33)
You can try using correlated subquery
DEMO
select distinct OutPutValue,type, status
from t2 a inner join t1 b on a.object_id=b.id
where type='c' and not exists
(select 1 from t2 a1 where a.object_id=a1.object_id and status<>33 and type='c')
OUTPUT:
OutPutValue type status
2018 c 33
Another solution could be the following :
SELECT T1.id, T1.outputvalue FROM tbl1 T1
JOIN (
SELECT tbl2.*, MAX(type), MAX(status)
FROM tbl2
GROUP BY object_id
HAVING
MIN(status) = MAX(status) AND
MIN(type) = MAX(type)
) T2 ON T1.id = T2.object_id
WHERE T2.type = 'c'
EDIT: I have updated my query to match a particular case which make it quite similar to another answer.
FIND A DEMO HERE
Try a join combined with an aggregation:
SELECT
t1.OutPutValue,
MAX(t2.type) AS type,
MAX(t2.status) AS status
FROM tbl1 t1
INNER JOIN tbl2 t2
ON t1.id = t2.object_id
GROUP BY
t1.id,
t1.OutPutValue
HAVING
MIN(t2.status) = MAX(t2.status) AND
MAX(t2.status) = 33 AND
MIN(t2.type) = MAX(t2.type) AND
MAX(t2.type) = 'c';

How to do an outer join with full result between two tables

I have two tables:
TABLE1
id_attr
-------
1
2
3
TABLE2
id | id_attr | val
----------------------
10 | 1 | A
10 | 2 | B
As a result I want a table that show:
RESULT
id | id_attr | val
----------------------
10 | 1 | A
10 | 2 | B
10 | 3 | NULL
So I want the row with id=10 and id_attr=3 also when id_Attr=3 is missing in TABLE2 (and I know that because I have a NULL value (or something else) in the val column of RESULT.
NB: I could have others ids in table2. For example, after insert this row on table2: {11,1,A}, as RESULT I want:
id | id_attr | val
----------------------
10 | 1 | A
10 | 2 | B
10 | 3 | NULL
11 | 1 | A
11 | 2 | NULL
11 | 3 | NULL
So, for every id, I want always the match with all id_attr.
Your specific example only has one id, so you can use the following:
select t2.id, t2.id_attr, t2.val
from table2 t2
union all
select 10, t1.id_attr, NULL
from table1 t1
where not exists (select 1 from table2 t2 where t2.id_attr = t1.id_attr);
EDIT:
You can get all combinations of attributes and ids in the following way. Use a cross join to create all the rows you want and then a left join to bring in the data you want:
select i.id, t1.id_attr, t2.val
from (select distinct id from table2) i cross join
table1 t1 left join
table2 t2
on t2.id = i.id and t2.id_attr = t1.id_attr;
It sounds like you want to do just an outer join on id_attr instead of id.
select * from table2 t2
left outer join table1 t1 on t2.id_attr = t1.id_attr;

How can I compare 2 different records based on 2 different criteria within a group in oracle?

I need to modify the following code to search for groups where one surv is null and the other is not. Currently, the query returns groups where both surv is populated. I am looking all groups where the surv for one record A does not match an id in the other record B, but only in cases where the surv in record B is null.
SELECT *
FROM MY_TABLE t3
WHERE t3.GROUP_id IN (
SELECT t1.GROUP_id
FROM MY_TABLE t1, MY_TABLE t2
WHERE t1.id <> t2.id
AND t1.GROUP_id = t2.GROUP_id
AND t1.id <> t2.surv
AND t2.id <> t1.surv
);
This is returning differences where both survs are populated. What am I missing?
edit:
---------------------------------
| group | id | surv |
----------------------------------
| 1 | 1 | null |
| 1| | 2 | 1 |
| 2 | 3 | 107 |
| 2 | 4 | null |
| 3 | 5 | 89 |
| 3 | 6 | 89 |
----------------------------------
return
---------------------------------
| group | id | surv |
----------------------------------
| 2 | 3 | 107 |
| 2 | 4 | null |
----------------------------------
reason:
group 1 has id 1 matches to surv of the second record; as such we do not want it returned.
group 2, id 3 has a surv that does not match the ID of the other record. Along with this, the second surv field is null. This is what we need returned.
group 3, both have a surv of not null. These are not needed.
edit 2: I eventually came up with this query:
SELECT cluster_id, oidmu, survoid
FROM MY_TABLE t3
WHERE t3.GROUP_id IN (
SELECT t1.GROUP_id
FROM MY_TABLE t1, MY_TABLE t2
WHERE t1.ID <> t2.ID
AND t1.GROUP_id = t2.GROUP_id
AND (t1.ID <> t2.SURV and t1.SURV is null)
);
add and t2.surv is null to your query.
SELECT *
FROM MY_TABLE t3
WHERE t3.GROUP_id IN (
SELECT t1.GROUP_id
FROM MY_TABLE t1, MY_TABLE t2
WHERE t1.id <> t2.id
AND t1.GROUP_id = t2.GROUP_id
AND t1.id <> t2.surv
AND t2.id <> t1.surv
and t2.surv is null
);
If you just want the groups, perhaps an aggregation will do:
SELECT t.GROUP_ID
FROM MY_TABLE t
GROUP BY GROUP_ID
HAVING COUNT(surv) > 0 AND -- at least one is not null
COUNT(surv) < COUNT(*); -- at least one is null
Actually, even if you do need the original rows, you could do this with analytic functions:
SELECT t.GROUP_ID
FROM (SELECT t.*, COUNT(*) OVER (PARTITION BY GROUP_ID) as cnt,
COUNT(surv) OVER (PARTITION BY GROUP_ID) as cnt_surv
FROM MY_TABLE t
) t
WHERE cnt_surv > 0 and cnt_surv < cnt

Select date from table with new column as result from other table

In SQL Server 2008, how can I retrieve data from table1 with new magic column (bit value), this new column take 'true' if current id from table1 exist in table2, else take 'false'.
For example :
Table1
id | name
-----------
10 | USA
11 | UK
12 | France
table2
id | title | fk
----------------------
1 | v1 | 10
2 | v2 | 10
3 | v3 | 11
result :
id | name | new column
----------------------------
10 | USA | true
11 | UK | true
12 | France | false
SELECT DISTINCT table1.id, table1.name,
CASE WHEN table2.id IS NULL THEN 'False' ELSE 'True' END AS mycolumn
FROM table1
LEFT OUTER JOIN table2
ON table1.id = table2.fk
You can use left join to get the data you want.
SQL
select A.*
,case when B.fk is not null then 'true' else 'false' end as [new column]
from table1 A
left join
(
select distinct fk from table2
)B on A.id=B.fk
OUTPUT
id name new column
10 USA true
11 UK true
12 France false
Read about different join types. this is basic SQL.
SELECT Table1.[id], [name], CASE WHEN Table2.[id] IS NULL THEN 0 ELSE 1 END As [New column]
FROM Table1 LEFT JOIN
Table2 ON(Table1.[id] = Table2.[fk])
The following query returns the expected result:
SELECT T1.*
,CAST(CASE
WHEN T2.id IS NOT NULL THEN 1
ELSE 0
END AS BIT) AS magic_column
FROM table1 T1
LEFT JOIN table2 T2 ON T1.id = T2.fk

MySQL: Typecasting NULL to 0

Let us suppose the following table (e.g. a result of several inner join statements):
id | column_1 | column_2
------------------------
1 | 1 |
2 | 2 | 2
3 | | 3
Which you could for example get from the following statement:
select a.id, t1.column_1, t2.column_2
from a
left join t1 on a.id = t1.id
left join t2 on a.id = t2.id
Now, if i'd like to sum up t1.column_1 and t2.column_2 as follows
select
a.id,
t1.column_1,
t2.column_2,
(t1.column_1 + t2.column_2) as cumulated
from a
left join t1 on a.id = t1.id
left join t2 on a.id = t2.id
The result will look as follows:
id | column_1 | column_2 | cumulated
------------------------------------
1 | 1 | NULL | NULL
2 | 2 | 2 | 4
3 | NULL | 3 | NULL
My question basically is: is there a way to typecast NULL into 0 in order to do some math?
I have tried CONVERT(t1.column_1, SIGNED) and CAST(t1.column_1 as SIGNED), but a NULL stays a NULL.
Use IFNULL(column, 0) to convert the column value to zero.
Alternatively, the COALESCE function will do the same thing: COALESCE(column, 0), except
COALESCE is ANSI-compliant, IFNULL is not
COALESCE takes an arbitrary number of columns/values and will return the first non-null value passed to it.