Value in column to equal other column with conditions - sql

Using SQL Server
The output I want: For the same values in column ID1, if there is a “null” in column ‘Value’ than make it equal to minimum(value) of that ID1.
I previously had a question relating to the following, although have still been unable to solve this!
Table 1
ID1
ID2
Value
1
1
0.1
1
2
2
1
3
null
2
5
0.2
2
5
null
3
7
6
Output I want
ID1
ID2
Value
1
1
0.1
1
2
2
1
3
0.1
2
5
0.2
2
5
0.2
3
7
6

you can use min() with window function
select ID1, ID2,
[Value] = coalesce(Value,
min(Value) over (partition by ID1))
from yourTable

WITH minimumValues AS (SELECT ID1, MIN(value) as value FROM table GROUP BY ID1)
SELECT
ID1,
ID2,
COALESCE( table1.Value, minimumValues.value) AS value
FROM table INNER JOIN
MinimumValues ON MinimumValues.ID1 = table.ID1

You can try the below to get the desired output -
Sample Table:
CREATE TABLE SampleData (
ID1 INT,
ID2 INT,
Value FLOAT
);
Sample Data:
INSERT INTO SampleData
(ID1, ID2, Value)
VALUES
(1, 1, 0.1),
(1, 2, 2),
(1, 3, NULL),
(2, 5, 0.2),
(2, 5, NULL),
(3, 7, 6);
Query:
WITH cte AS (
SELECT ID1, MIN(Value) AS MinValue
FROM SampleData
WHERE Value IS NOT NULL
GROUP BY ID1
)
SELECT t.ID1, t.ID2, COALESCE(t.Value, cte.MinValue) AS Value
FROM SampleData t
JOIN cte ON t.ID1 = cte.ID1

Related

how to get unique data from multiple columns in db2

I wanted to get data from 2 columns in below way:
Id1 id2 id3
1 1 2
2 3 null
2 4 null
O/p
Id1 data
1 1,2
2 3,4
Here id1 is pk and id2 and id3 is fk of other table.
Try this as is:
WITH TAB (ID1, ID2, ID3) AS
(
VALUES
(1, 1, 2)
, (2, 3, NULL)
, (2, 4, NULL)
)
SELECT ID1, LISTAGG(DISTINCT ID23, ',') AS DATA
FROM
(
SELECT T.ID1, CASE V.ID WHEN 2 THEN T.ID2 ELSE T.ID3 END AS ID23
FROM TAB T
CROSS JOIN (VALUES 2, 3) V(ID)
)
WHERE ID23 IS NOT NULL
GROUP BY ID1;
This is a bit strange -- concatenating both within the same row and across multiple rows. One method is to unpivot and then aggregate:
select id1, listagg(id2, ',') within group (order by id2)
from (select id1, id2 from t union all
select id1, id3 from t
) t
where id2 is not null
group by id1;
Assuming that only id2 could be NULL, you can also express this as:
select id1,
listagg(concat(id2, coalesce(concat(',', id3), '')), ',') within group (order by id2)
from t
group by id1;

SQL - Sum values when there is null

I have the following table:
RowID Column1 Column2
1 3 2
2 5 2
3 2 9
4 5 NULL
5 8 NULL
6 9 3
7 1 NULL
I need first row of Column1 to Sum every time there is a NULL value in Column2. And it would continue the logic down the rows.
So, the result should look like:
RowID Column1 Column2
1 3 2
2 5 2
3 15 9
4 5 NULL
5 8 NULL
6 10 3
7 1 NULL
Notice Row 3 summed 2+5+8 =15 and Row 6 summed 9+1 =10. So, basically the row prior to Null value in Column2 summed the values in column1 until there was no more NULL values in column2. Then it resumed in row 6 where the next value was NULL.
This will do it. I have set up the data in a table variable for demo.
declare #t table(RowID int, C1 int, C2 int)
insert #t values (1, 3, 2)
,(2, 5, 2)
,(3, 2, 9)
,(4, 5, NULL)
,(5, 8, NULL)
,(6, 9, 3)
,(7, 1, NULL)
select RowID, sum(C1), max(C2)
from (
select RowID, C1, C2 from #t
union all
select T1.RowID, T2.C1, null
from #t t1
join #t t2 on t2.RowID>t1.RowID and t2.C2 is null
and not exists(
select * from #t t3
where t3.RowID>t1.RowID and t3.c2 is not null and t3.RowID<t2.RowID
)
where T1.C2 is not null
) q group by RowID
Result:
RowID C1 C2
1 3 2
2 5 2
3 15 9
4 5 NULL
5 8 NULL
6 10 3
7 1 NULL
I got it. You need to look at the rows in reverse order, assigning the NULL values to the value before them.
The idea is to assign a group to the rows to sum. This is the number of non-NULL values following the row. With this, you can then use a window function to aggregate:
select t.*,
(case when c2 is null then c1
else sum(c1) over (partition by grp)
end) as new_c1
from (select t.*, count(c2) over (order by rowid rows between 1 following and unbounded following) as grp
from t
) t
order by rowid;
Here is a db<>fiddle.

update row same as row above if condition meet with number

i have data like this
id type
1. a
2. b
3. c
4. c
5. d
6. c
7. c
target
id type. group
1. a. 1
2. b. 2
3. c. 2
4. c. 2
5. d. 3
6. c. 3
7. c. 3
if type c, group value take value from above row.
i can goal this with loop condition and update but that take to much time because looping update many row
how can i achiev this with single update statement with sql server 2008
This should work
declare #t table (id int primary key, val char(1));
insert into #t values
(1, 'a')
, (2, 'b')
, (3, 'c')
, (4, 'c')
, (5, 'd')
, (6, 'c')
, (7, 'c');
select *
, sum(case when val = 'c' then 0 else 1 end) over (order by id) as grp
from #t t
order by id;
id val grp
----------- ---- -----------
1 a 1
2 b 2
3 c 2
4 c 2
5 d 3
6 c 3
7 c 3
Follow the link below for a running demo.
Demo
I am posting this as an alternative to the answer given by #palarazzi which may already be sufficient. This answer is robust to type letters occurring in any amount.
WITH cte AS (
SELECT t1.id AS id1, t1.type AS type1, t2.id AS id2, t2.type AS type2
FROM yourTable t1
INNER JOIN yourTable t2
ON (t1.id = t2.id AND t1.type <> 'c') OR
(t1.id > t2.id AND t1.type = 'c' AND t2.type <> 'c')
),
cte2 AS (
SELECT id1, type2,
ROW_NUMBER() OVER (PARTITION BY id1 ORDER BY id2 DESC) rn
FROM cte
)
SELECT
id1 AS id, type2 AS type,
DENSE_RANK() OVER (ORDER BY type2) [group]
FROM cte2
WHERE rn = 1;
Demo

Return Nth Percentile row value of a column that is an aggregate value

Related to SQL-Server
I need to return the value for a column in the Nth percentile associated to multiple unique IDs in another column. For example, for the dataset below, I need the value in the 80th Percentile in COL B for each unique value in COL A:
COL A COL B
--------- --------
A 2
A 4
A 6
A 8
A 10
B 2
B 2
B 3
B 5
B 7
B 8
B 11
B 13
B 17
B 18
The desired output would be:
COL A COL B
-------- --------
A 8
B 13
This is based on the logic that:
the 80th Percentile value for COL B is the 4th row value of 8 for value A in COL A;
and that the 80th Percentile value for COL B is the 8th row value of 13 for value B in COL A
If you're on SQL 2012 or greater, you can use percentile_disc()
WITH cte AS (
SELECT * FROM (VALUES
('A', 2 ),
('A', 4 ),
('A', 6 ),
('A', 8 ),
('A', 10 ),
('B', 2 ),
('B', 2 ),
('B', 3 ),
('B', 5 ),
('B', 7 ),
('B', 8 ),
('B', 11 ),
('B', 13 ),
('B', 17 ),
('B', 18 )
) AS x(a, v)
)
SELECT DISTINCT a
, PERCENTILE_DISC(0.8) WITHIN GROUP (ORDER BY v) OVER (PARTITION BY a)
FROM cte
Here is the absolutely wretched query:
select r.t1, MIN(r.t2) FROM (SELECT TOP 20 PERCENT t1, t2 FROM tempTable where t1 = 'A' ORDER BY t2 desc ) as r
group by r.t1
union
SELECT s.t1, MIN(s.t2) FROM ( SELECT TOP 20 PERCENT t1, t2 FROM tempTable ORDER BY t2 DESC ) as s
group by s.t1
Where t1 is Col A, t2 is Col B, and tempTable is your table.
This is solely based on your table provided and is by no means generic.
EDIT: I figured out how to apply it to the OP's question by using ntile
SELECT colA, colB,
NTILE(5) OVER(PARTITION BY colA ORDER BY colB DESC) AS 'tileN'
FROM tempTable t
group by colA, colB ) as n
where n.tileN = 2
What it does:
NTile basically creates partitions of 100 / a where a is NTILE(a). By dividing by 5 we get partitions of 20 percent. Therefore 2 is the 80th percentile. Then we select the top 20 percent from that query to eliminate values that would be the same.

How to select multi record depending on some column's condition?

Say there is a SQL Server table which contain 2 columns: ID, Value
The sample data looks like this:
ID value
------------------
1 30
1 30
2 50
2 50
3 50
When I run this query:
select ID, NEWID(), value
from table1
order by ID
The result looks like this:
1 30 E152AD19-9920-4567-87FF-C4822FD9E485
1 30 54F28C58-ABA9-4DFB-9A80-CE9C4C390CBB
2 50 ........
2 50 ........
3 50 4E5A9E26-FEEC-4CC7-9AC5-96747053B6B2
But what I want is : how many record of ID depending on (sum of value /30 )'s result, for example of ID 2, it's value's sum is 50+50=100, and 100/30=3, so ID 2 will display in query result three times
The final result i want is like this:
1 E152AD19-9920-4567-87FF-C4822FD9E485
1 54F28C58-ABA9-4DFB-9A80-CE9C4C390CBB
2 4E5A9E26-FEEC-4CC7-9AC5-96747053B6B2
2 ....
2 ....
3 D861563E-E01A-4198-9E92-7BEB4678E5D1
Please note ID of 2 display three times, wait for your helps, thanks.
How about something like
CREATE TABLE Table1
([ID] int, [value] int)
;
INSERT INTO Table1
([ID], [value])
VALUES
(1, 30),
(1, 30),
(2, 50),
(2, 50),
(3, 50)
;
;WITH SummedVals AS (
SELECT ID,
SUM(value) / 30 Cnt
FROM Table1
GROUP BY ID
)
, Vals AS (
SELECT ID,
Cnt - 1 Cnt
FROM SummedVals
UNION ALL
SELECT ID,
Cnt - 1 Cnt
FROM Vals
WHERE Cnt > 0
)
SELECT ID,
NEWID()
FROM Vals
ORDER BY 1
SQL Fiddle DEMO