I want to update every row in a table in Postgres and set each row to a different value; this value is gonna be an incremental value with a start value.
For instance, suppose I have table tab_a with the following data:
|attr_a|attr_b|
|1 |null |
|2 |null |
|3 |null |
|4 |null |
The output I might want is:
|attr_a|attr_b|
|1 |5 |
|2 |6 |
|3 |7 |
|4 |8 |
Here is my script:
UPDATE tab_a
SET attr_b = gen.id
FROM generate_series(5,8) AS gen(id);
However is not working as expected...
You could do
UPDATE tab_a upd
SET attr_b = row_number + 4 -- or something like row_number + (select max(attr_a) from tab_a)
FROM (
SELECT attr_a, row_number() over ()
FROM tab_a
ORDER BY 1
) a
WHERE upd.attr_a = a.attr_a;
Do something like this
UPDATE pr_conf_item upd
SET item_order = a.row_number
FROM (
SELECT id, row_number() over ()
FROM pr_conf_item
ORDER BY 1
) a
WHERE upd.id = a.id;
Related
Background
I'm a novice SQL user. Using PostgreSQL 13 on Windows 10 locally, I have a table t:
+--+---------+-------+
|id|treatment|outcome|
+--+---------+-------+
|a |1 |0 |
|a |1 |1 |
|b |0 |1 |
|c |1 |0 |
|c |0 |1 |
|c |1 |1 |
+--+---------+-------+
The Problem
I didn't explain myself well initially, so I've rewritten the goal.
Desired result:
+-----------------------+-----+
|ever treated |count|
+-----------------------+-----+
|0 |1 |
|1 |3 |
+-----------------------+-----+
First, identify id that have ever been treated. Being "ever treated" means having any row with treatment = 1.
Second, count rows with outcome = 1 for each of those two groups. From my original table, the ids who are "ever treated" have a total of 3 outcome = 1, and the "never treated", so to speak, have 1 `outcome = 1.
What I've tried
I can get much of the way there, I think, with something like this:
select treatment, count(outcome)
from t
group by treatment;
But that only gets me this result:
+---------+-----+
|treatment|count|
+---------+-----+
|0 |2 |
|1 |4 |
+---------+-----+
For the updated question:
SELECT ever_treated, sum(outcome_ct) AS count
FROM (
SELECT id
, max(treatment) AS ever_treated
, count(*) FILTER (WHERE outcome = 1) AS outcome_ct
FROM t
GROUP BY 1
) sub
GROUP BY 1;
ever_treated | count
--------------+-------
0 | 1
1 | 3
db<>fiddle here
Read:
For those who got no treatment at all (all treatment = 0), we see 1 x outcome = 1.
For those who got any treatment (at least one treatment = 1), we see 3 x outcome = 1.
Would be simpler and faster with proper boolean values instead of integer.
(Answer to updated question)
here is an easy to follow subquery logic that works with integer:
select subq.ever_treated, sum(subq.count) as count
from (select id, max(treatment) as ever_treated, count(*) as count
from t where outcome = 1
group by id) as subq
group by subq.ever_treated;
I got a table looking like this
+-----+---------+
|Group|Value |
+-----+---------+
|A |1 |
+-----+---------+
|B |2 |
+-----+---------+
|C |1 |
+-----+---------+
|D |3 |
+-----+---------+
And I would like to add a column in my select command that count GROUP based on value, lookin like this:
+-----+---------+---------+
|Group|Value | COUNT |
+-----+---------+---------+
|A |1 |2 |
+-----+---------+---------+
|B |2 |1 |
+-----+---------+---------+
|C |1 |2 |
+-----+---------+---------+
|D |3 |1 |
+-----+---------+---------+
Value 1 got the two groups A and C the other values for each one in this example.
Additional is it possible to consider all values for VALUES and GROUP even if a WHERE filtered out some of them in the select query?
You want a window function:
select t.*, count(*) over (partition by value) as count
from t;
You have a problem if the query has a where clause. The where applies to the window function. So you need a subquery for the count:
select t.*
from (select t.*, count(*) over (partition by value) as count
from t
) t
where . . .;
Or a correlated subquery might be convenient under some circumstances:
select t.*,
(select count(*) from t t2 where t2.value = t.value) as count
from t
where . . .;
I have a doubt on a SQL query:
I have the following result from a query:
select distinct eb.event_type_id, eb.status from eid.event_backlog eb order by 1
|event_type_id|status |
|-------------|----------|
|1 |SUCCESS |
|2 |SUCCESS |
|2 |ERROR |
|3 |SUCCESS |
|3 |ERROR |
|4 |SUCCESS |
i would like to obtain this result doing a distinct on the status:
|event_type_id|count |
|-------------|-------|
|1 |1 |
|2 |2 |
|3 |2 |
|4 |1 |
but the only way that I see to obtain this result is doing the following query:
select
eb.event_type_id,
count(1)
from
(
select
distinct eb.event_type_id, eb.status
from
eid.event_backlog eb
order by
1) eb
group by
eb.event_type_id
I don't like to use an nestled query, there is another way to obtain what i want?
Simply count(distinct eb.status), i.e.
select
eb.event_type_id,
count(distinct eb.status)
from eid.event_backlog eb
group by
eb.event_type_id
I have this table categories
|catId |catName|catParentID|catType|
-------------------------------------
|1 |cat1 |null |6 |
|2 |cat2 |null |9 |
|3 |cat3 |1 |6 |
|4 |cat4 |2 |9 |
|5 |cat5 |1 |6 |
|6 |cat6 |3 |8 |
the parents are in the same table with the sub categories only they have no parent.
i need to get all the sub categories that their parent's type is 6.
the output of the example above should look like this-
cat3
cat5
Given your data structure, this seems to work:
select c.*
from categories c
where c.catParentID is not null and -- has a parent
c.catType = 6;
However, that might not be a general solution. So you can use a self-join:
select c.*
from categories c join
categories cp
on c.catParentID = cp.catID
where cp.catType = 6;
SELECT *
FROM categories
WHERE cattype = 6
AND catparentid IS NOT NULL
The Simplest way is,
SELECT * FORM categories WHERE catParentId ='1' AND catType ='6'
Try this... (Based on your desired output)
SELECT t1.*
FROM tablename t1
LEFT JOIN tablename t2 ON t1.catparentid = t2.catid
WHERE t2.cattype = 6
AND t2.catparentid IS NULL
i have table with id column and param column
and i try to add some param only where this param not exist
for example my table is:
+--+-----+
|id|param|
+--+-----+
|2 |a |
+--+-----+
|2 |b |
+--+-----+
|3 |a |
+--+-----+
|3 |b |
+--+-----+
|4 |a |
+--+-----+
|4 |b |
+--+-----+
|4 |c |
+--+-----+
now i try to add "c" param to all id's that don't have c param
how i can do it in one sql query?
(the param that i wont to add it hard coded like "c" in the example param and i dont need to take it from any other table...)
You can do this with insert . . . select. The select part just needs to find the ids that do not have that parameter:
insert into t(id, param)
select id, 'C'
from t
group by id
having sum(case when param = 'C' then 1 else 0 end) = 0;
You could do this with MERGE ... SELECT inserting when there is no match.
MERGE INTO mytable t
USING ( SELECT DISTINCT id, 'C'
FROM mytable
) as i (key, val)
ON id=key and param=val
WHEN NOT MATCHED THEN
INSERT (id,param) VALUES (key,val)