I have this audit table
User
date
text
text 2
u1
2023-01-01
hi
yes
u1
2022-12-20
hi
no
u1
2022-12-01
hello
maybe
And I need as a result, something like this:
User
date
text
text 2
u1
2023-01-01
null
x
u1
2022-12-20
x
x
u1
2022-12-01
null
null
So I can know which column changed from the last time.
Something like this is working, but I think may be a way to optimize it? or at least generate a "more easy to look" query? (i need the information for almost 20 columns, not only 3)
SELECT
ta.audit_date,
ta.audit_user,
CASE
WHEN ta.audit_operation = 'I' THEN 'Insert'
WHEN ta.audit_operation = 'U' THEN 'Update'
END AS action,
CASE WHEN ta.column1 <> (SELECT column1
FROM audit_table ta1
WHERE ta1.id = 9207 AND ta1.audit_date < ta.audit_date
ORDER BY ta1.audit_date DESC
LIMIT 1)
THEN 'X' ELSE null END column1,
CASE WHEN ta.column2 <> (SELECT column2
FROM audit_table ta1
WHERE ta1.id = 9207 AND ta1.audit_date < ta.audit_date
ORDER BY ta1.audit_date DESC
LIMIT 1)
THEN 'X' ELSE null END column2,
CASE WHEN ta.column3 <> (SELECT column3
FROM audit_table ta1
WHERE ta1.id = 9207 AND ta1.audit_date < ta.audit_date
ORDER BY ta1.audit_date DESC
LIMIT 1)
THEN 'X' ELSE null END column3
FROM
audit_table ta
WHERE
ta.id = 9207
ORDER BY
audit_date DESC
Thank you!
I think you can just use the LAG() analytic function here. If I understand correctly:
SELECT *, CASE WHEN text != LAG(text) OVER (ORDER BY date) THEN 'x' END AS text_label,
CASE WHEN text2 != LAG(text) OVER (ORDER BY date) THEN 'x' END AS text2_label
FROM yourTable
ORDER BY date;
I have Car table. Car has is_sold and is_shipped. A Car belongs to a dealership, dealership_id (FK).
I want to run a query that tells me the count of sold cars and the count of shipped cars for a given dealership all in one result.
sold_count | shipped_count
10 | 4
The single queries I have look like this:
select count(*) as sold_count
from car
where dealership_id=25 and is_sold=true;
and
select count(*) as shipped_count
from car
where dealership_id=25 and is_shipped=true;
How do I combine the two to get both counts in one result?
This will do:
select dealership_id,
sum(case when is_sold is true then 1 else 0 end),
sum(case when is_shipped is true then 1 else 0 end)
from cars group by dealership_id;
You can use the filter clause of the Aggregate function. (see demo)
select dealership_id
, count(*) filter (where is_sold) cars_sold
, count(*) filter (where is_shipped) cars_shipped
from cars
where dealership_id = 25
group by dealership_id;
You can also using cross join.
select 'hello' as col1, 'world' as col2;
return:
col1 | col2
-------+-------
hello | world
(1 row)
similarly,
with a as
(
select count(*) as a1 from emp where empid> 5),
b as (
select count(*) as a2 from emp where salary > 6000)
select * from a, b;
or you can even apply to different table. like:
with a as
(select count(*) as a1 from emp where empid> 5),
b as
(select count(*) as a2 from ab )
select * from a, b;
with a as
(
select count(*) as sold_count
from car
where dealership_id=25 and is_sold=true
),
b as
(
select count(*) as shipped_count
from car
where dealership_id=25 and is_shipped=true
)
select a,b;
further reading: https://www.postgresql.org/docs/current/queries-table-expressions.html.
https://stackoverflow.com/a/26369295/15603477
I want to turn
TABLEA:
id type amount
A 'Customer' 100
A 'Parter' 10
A 'Customer' 200
A 'Parter' 20
B 'Parter' 555
I can hardcode the type, don't need to be dynamic, these types are enum
RESULT:
id customer_array customer_sum partner_array partner_sum
A [100, 200] 300 [10, 20] 30
B [] 0 [555] 555
Right now
I am using two aggregate function
WITH customer AS (
SELECT
table_A,
json_agg(row_to_json(amount)) AS customer_array,
sum(amount) AS customer_sum
FROM table_A WHERE type='Customer'
GROUP BY id
), partner AS (
SELECT
table_A,
json_agg(row_to_json(amount)) AS partner_array,
sum(amount) AS partner_sum
FROM table_A WHERE type='Partner'
GROUP BY id
) SELECT
id,
COALESCE(customer_array, '[]') AS customer_array,
COALESCE(customer_sum, 0) AS customer_sum,
COALESCE(partner_array, '[]') AS partner_array,
COALESCE(partner_sum, 0) AS partner_sum
FROM customer FULL OUTER JOIN partner USING (id)
I am wondering if there is a way to achieve what I want without querying twice?
This is a simple conditional aggregation as far as I can tell:
select id,
array_agg(amount) filter (where type = 'Customer') as customer_array,
sum(amount) filter (where type = 'Customer') as customer_sum,
array_agg(amount) filter (where type = 'Partner') as partner_array,
sum(amount) filter (where type = 'Partner') as partner_sum
from table_a
group by id;
If you want an empty array instead of a NULL value, wrap the aggregation functions into a coalesce():
select id,
coalesce((array_agg(amount) filter (where type = 'Customer')),'{}') as customer_array,
coalesce((sum(amount) filter (where type = 'Customer')),0) as customer_sum,
coalesce((array_agg(amount) filter (where type = 'Partner')),'{}') as partner_array,
coalesce((sum(amount) filter (where type = 'Partner')),0) as partner_sum
from table_a
group by id;
You can try using the case statement.
https://www.postgresql.org/docs/8.2/static/functions-conditional.html
I don't have a postgres server to try this. But overall the syntax should be as below.
SELECT
table_A,
case
when Type='Customer'
then json_agg(row_to_json(amount))
else []
end AS customer_array,
case
when Type='Customer'
sum(amount)
else 0
end
AS customer_sum,
case
when Type='Partner'
then json_agg(row_to_json(amount))
else []
end AS partner_array
case
when Type='Partner'
sum(amount)
else 0
end
From table_A
GROUP BY id
UPDATE amc_machine b
SET with_parts = a.with_parts,
amc_validity_upto = a.amc_validity_upto
FROM (SELECT CASE
WHEN count(*) > 0 THEN (SELECT DISTINCT ON (machine_id) with_parts, amc_validity_upto, machine_id
FROM amc_amcdetail
WHERE machine_id = 2 AND id != 1
ORDER BY machine_id, amc_validity_upto DESC)
WHEN count(*) = 0 THEN (SELECT FALSE AS with_parts, NULL AS amc_validity_upto, 2 AS machine_id)
END AS a
FROM (SELECT DISTINCT ON (machine_id) with_parts, amc_validity_upto, machine_id
FROM amc_amcdetail
WHERE machine_id = 2
ORDER BY machine_id, amc_validity_upto
) AS T) AS foo
WHERE a.machine_id = b.id
The error shown is
ERROR: subquery must return only one column
LINE 5: WHEN count(*) > 0 THEN (SELECT DISTINCT ON (machine_id) w...
Can anyone tell what seems to be the problem.
Basically the query is to update on table b with data from table a if exists, else update with null , false as the case is.
The query executes when standalone. I am using Postgres 9.3, but deployment will be on postgres9.1
The subquery returns 3 columns
SELECT DISTINCT ON (machine_id) with_parts, amc_validity_upto, machine_id
Make it return only one
SELECT DISTINCT ON (machine_id) with_parts
I have below table in SQL server 2008.Please help to get expected output
Thanks.
CREATE TABLE [dbo].[Test]([Category] [varchar](10) NULL,[Value] [int] NULL,
[Weightage] [int] NULL,[Rn] [smallint] NULL ) ON [PRIMARY]
insert into Test values ('Cat1',310,674,1),('Cat1',783,318,2),('Cat1',310,96,3),('Cat1',109,917,4),('Cat2',441,397,1),('Cat2',637,725,2),('Cat2',460,742,3),('Cat2',542,583,4),('Cat2',601,162,5),('Cat2',45,719,6),('Cat2',46,305,7),('Cat3',477,286,1),('Cat3',702,484,2),('Cat3',797,836,3),('Cat3',541,890,4),('Cat3',750,962,5),('Cat3',254,407,6),('Cat3',136,585,7),('Cat3',198,477,8),('Cat4',375,198,1),('Cat4',528,351,2),('Cat4',845,380,3),('Cat4',716,131,4),('Cat4',781,919,5)
For per category Average Weightage
SELECT
Category,
AVG(Value),
SUM(CASE WHEN RN<4 THEN Weightage ELSE 0 END) / (NULLIF(SUM(CASE WHEN RN<4 THEN 1 ELSE 0 END), 0))
FROM
MyTable
GROUP BY
Category
Average Weightage over the whole set
SELECT
M.Category,
AVG(Value),
foo.AvgWeightage
FROM
MyTable M
CROSS JOIN
(SELECT AVG(Weightage) As AvgWeightage FROM MyTable WHERE Rn < 4) foo
GROUP BY
M.Category, foo.AvgWeightage
Simple:)
SELECT Category,
AVG(Value) AS AvgValue,
AVG(CASE WHEN RN< 4 THEN (Weightage) END ) AS AvgWeightage
FROM Test
GROUP BY Category
Try this
SELECT AvgValue.Category, AvgValue.AvgValue, AvgWeight.Weight
FROM(
(SELECT c.Category,
AVG(c.Value) AS AvgValue
FROM Test c
GROUP BY Category) AvgValue
INNER JOIN
(SELECT Category, AVG(Weightage) AS Weight
FROM Test
WHERE Rn < 4
GROUP BY Category) AvgWeight
ON AvgValue.Category = AvgWeight.Category)