Getting type cast issue when adding up the values from an array (array_agg) - postgresql

I was trying to sum up all the values from an array in PostgreSQL, tried different way but always getting the issue function sum(numeric[]) does not exist. Even I have tried with casting, but still that shows the same issue. Am I missing anything here?.
select array_to_json(array_agg(items)) FROM (SELECT SUM(p.total_price) FROM (SELECT
ARRAY_AGG(cart_items.unit_price) FILTER (where cart_items.type = 2) AS total_price
from cart inner join cart_items on cart_items.cart_id = cart.id where cart.id =
40868884) AS p) AS items;
Result is:
array_to_json
-------------------------------------------------------------------------------------------------
[{"total_price":[1.867,1.867,1.867,1.867,1.867,1.21,1.867,1.867,1.56,1.867,1.867,1.867,44]}]
Basically, I want to sum up these values of the column prices after taking it from the database.
Fiddle
http://sqlfiddle.com/#!17/3fdd3/4

If what you want to do is sum up the prices in your json "totalprice" fields, then you can use:
select t.*,
(select sum(price)
from (select json_array_elements_text(j.el->'total_price')::numeric as price
from json_array_elements(t.x) j(el)
) j
)
from (select '[{"total_price":[1.867,1.867,1.867,1.867,1.867,1.21,1.867,1.867,1.56,1.867,1.867,1.867,44]}]'::json as x) t

Related

How to make a Select sentence with acumulate in final column

I'm trying to make a query for acum the sum of one of fields in a new column, but i dont get it in SqlServer 2008 r2
I have the next table:
Fields: id,Codigo,tipo,cantidad
I want to make a query for get the next result
When the field tipo is 2, the acum begins
Is it possible?
Thanks.
finally i found a good sentence for me
with AcumulaCant as (
select
d.idrecno,
d.tipmov,
d.codart,
d.codalm,
d.cant
from movsto d
)
select *,
CantAcum = (
select SUM(cant)
from AcumulaCant c
where c.idrecno <= AcumulaCant.idrecno
and c.codart = AcumulaCant.codart
and c.codalm = AcumulaCant.codalm),
ROW_NUMBER() over(partition by codart,codalm order by idrecno desc) as rn
from AcumulaCant
order by AcumulaCant.codart,AcumulaCant.codalm,AcumulaCant.idrecno desc
With this sentence i get the acum of the sum quantities by ref.
Thanks to all for your comments.

Delete duplicate rows based on columns

I have a table called Aircraft and there are many records. The problem is that some are duplicates. I know how to select the duplicates and their counts:
SELECT flight_id, latitude, longitude, altitude, call_sign, measurement_time, COUNT(*)
FROM Aircraft
GROUP BY flight_id, latitude, longitude, altitude, call_sign, measurement_time
HAVING COUNT(*) > 1;
This returns something like:
Now, what I need to do is remove the duplicates, leaving just one each so that when I run the query again, all counts become 1.
I know that I can use the DELETE keyword, but I'm not sure how to delete it from the SELECT.
I'm sure I am missing an easy step, but I do not want to ruin my DB being a newbie.
How do I do this?
SELECT
flight_id, latitude, longitude, altitude, call_sign, measurement_time
FROM Aircraft a
WHERE EXISTS (
SELECT * FROM Aircraft x
WHERE x.flight_id = a.flight_id
AND x.latitude = a.latitude
AND x.longitude = a.longitude
AND x.altitude = a.altitude
AND x.call_sign = a.call_sign
AND x.measurement_time = a.measurement_time
AND x.id < a.id
)
;
If the query above returns thecorrect rows (to be deleted)
you can change it into a delete statement:
DELETE
FROM Aircraft a
WHERE EXISTS (
SELECT * FROM Aircraft x
WHERE x.flight_id = a.flight_id
AND x.latitude = a.latitude
AND x.longitude = a.longitude
AND x.altitude = a.altitude
AND x.call_sign = a.call_sign
AND x.measurement_time = a.measurement_time
AND x.id < a.id
)
;
I have always used the CTE method in SQL SERVER. This allows you to define columns that you want to compare, once you have established what columns make up a duplicate, then you can assign a CTE value to it and then go back and cleanup the CTE values that are greater than 1. This is an example of duplicate checking that I do.
WITH CTE AS
(select d.UID
,d.LotKey
,d.SerialNo
,d.HotWeight
,d.MarketValue
,RN = ROW_NUMBER()OVER(PARTITION BY d.HotWeight, d.serialNo, d.MarketValue order by d.SerialNo)
from LotDetail d
where d.LotKey = ('1~20161019~305')
)
DELETE FROM CTE WHERE RN <> 1
In my example I am looking at the LotDetail table where the d.hotweight and d.serial no are matching. if there is a match then the original gets CTE 1 and any duplicates get CTE 2 or greater depending on the amount of duplicates. Then you use the last DELETE statement to clear the entries that come up as duplicate. THis is really flexible so you should be able to adapt it to your issue.
Here is an example tailored to your situation.
WITH CTE AS
(select d.Flight_ID
,d.Latitude
,d.Longitude
,d.Altitude
,d.Call_sign
,d.Measurement*
,RN = ROW_NUMBER()OVER(PARTITION BY d.Flight_ID, d.Latitude, d.Longitude, d.Altitude, d.Call_Sign, d.Measurement* order by d.SerialNo)
from Aircraft d
where d.flight_id = ('**INSERT VALUE HERE')
)
DELETE FROM CTE WHERE RN <> 1
If it's a one-time operation you can create a temp table with the same schema and then copy unique rows over like so:
insert into Aircraft_temp
select distinct on (flight_id, measurement_time) Aircraft.* from Aircraft
Then swap them out by renaming, or truncate Aircraft and copy the temp contents back (truncate Aircraft; insert into Aircraft select * from Aircraft_temp;).
Safer to rename Aircraft to Aircraft_old and Aircraft_temp to Aircraft so you keep your original data until you are sure things are correct. Or at least check that the number of rows in your count query above match the count of rows in the temp table before doing the truncate.
Update2: With a separate valid primary key (assuming it is called id) you can do a DELETE based on a self join like this:
delete from Aircraft using (
select a1.id
from Aircraft a1
left join (select flight_id, measurement_time, min(id) as id from Aircraft group by 1,2) a2
on a1.id = a2.id
where a2.id is null
) as d
where Aircraft.id=d.id
This finds the minimum id (could do max too for the "latest") for each flight and identifies all the records from the full set having an id that is not the minimum (no match in the join). The unmatched ids are deleted.

Updating a CTE table fail cause of derived or constant field

I'm using MS-SQL 2012
WITH C1
(
SELECT ID, 0 as Match, Field2, Count(*)
FROM TableX
GROUP BY ID, Fields2
)
UPDATE C1 SET Match = 1
WHERE ID = (SELECT MATCHING_ID FROM AnotherTable WHERE ID = C1.ID)
This TSQL statement gives me the following error:
Update or insert of view or function 'C1' failed because it contains a derived or constant field.
Ideally I would like to create a "fake field" named Match and set its default value to 0. Then with the update I would like to Update ONLY the records that have an existing entry on the "AnotherTable".
Any thoughts what am I doing wrong?
Thanks in advanced.
Try doing a Left Outer Join like
SELECT x.ID, ISNULL(a.Matching_ID, 0) as Match, x.Field2, Count(*)
FROM TableX x
LEFT OUTER JOIN AnotherTable a on x.ID = a.ID
GROUP BY x.ID, ISNULL(a.Matching_ID, 0), x.Fields2
without the need of a C1
If I am understanding correctly, the problem is that you are trying to update the CTE table. If you update the table directly you should be fine.
Does this modified version help?
SELECT t.ID
, CASE WHEN (EXISTS (SELECT MATCHING_ID FROM AnotherTable WHERE ID = t.ID)) THEN 1 ELSE 0 END
,t.Field2
,Count(*)
FROM TableX t
GROUP BY ID, Fields2

Need better summation select statement in postgres function

I've got two tables in my database. One of them, 'orders', contains a set of columns with an integer which represents what the order should contain (like 5 of A and 15 of B). The second table, 'production_work', contains those same order columns, and a date, so whenever somebody completes part of an order, I track it.
So now i need a fast way to know which orders are completed, and I'm hoping to avoid a 'completed' table on the first column as orders are editable and it's just more logic to keep correct.
This query works, but it's horribly written. What's a better way to do this? There are actually 12 of these columns that go into this query...I'm just showing 3 of them for the example.
SELECT *
FROM orders o
WHERE ud = (SELECT SUM(ud) FROM production_work WHERE order_id = o.ident)
AND dp = (SELECT SUM(dp) FROM production_work WHERE order_id = o.ident)
AND swrv = (SELECT SUM(swrv) FROM production_work WHERE order_id = o.ident)
select o.*
from
orders o
inner join
(
select order_id, sum(ud) as ud, sum(dp) as dp, sum(swrv) as swrv
from production_work
group by order_id
) pw on o.ident = pw.order_id
where
o.ud = pw.ud
and o.dp = pw.dp
and o.swrv = pw.swrv

Simple SELECT, but adding JOIN returns too many rows

The query below returns 9,817 records. Now, I want to SELECT one more field from another table. See the 2 lines that are commented out, where I've simply selected this additional field and added a JOIN statement to bind this new columns. With these lines added, the query now returns 649,200 records and I can't figure out why! I guess something is wrong with my WHERE criteria in conjunction with the JOIN statement. Please help, thanks.
SELECT DISTINCT dbo.IMPORT_DOCUMENTS.ITEMID, BEGDOC, BATCHID
--, dbo.CATEGORY_COLLECTION_CATEGORY_RESULTS.CATEGORY_ID
FROM IMPORT_DOCUMENTS
--JOIN dbo.CATEGORY_COLLECTION_CATEGORY_RESULTS ON
dbo.CATEGORY_COLLECTION_CATEGORY_RESULTS.ITEMID = dbo.IMPORT_DOCUMENTS.ITEMID
WHERE (BATCHID LIKE 'IC0%' OR BATCHID LIKE 'LP0%')
AND dbo.IMPORT_DOCUMENTS.ITEMID IN
(SELECT dbo.CATEGORY_COLLECTION_CATEGORY_RESULTS.ITEMID FROM
CATEGORY_COLLECTION_CATEGORY_RESULTS
WHERE SCORE >= .7 AND SCORE <= .75 AND CATEGORY_ID IN(
SELECT CATEGORY_ID FROM CATEGORY_COLLECTION_CATS WHERE COLLECTION_ID IN (11,16))
AND Sample_Id > 0)
AND dbo.IMPORT_DOCUMENTS.ITEMID NOT IN
(SELECT ASSIGNMENT_FOLDER_DOCUMENTS.Item_Id FROM ASSIGNMENT_FOLDER_DOCUMENTS)
One possible reason is because one of your tables contains data at lower level, lower than your join key. For example, there may be multiple records per item id. The same item id is repeated X number of times. I would fix the query like the below. Without data knowledge, Try running the below modified query.... If output is not what you're looking for, convert it into SELECT Within a Select...
Hope this helps....
Try this SQL: SELECT DISTINCT a.ITEMID, a.BEGDOC, a.BATCHID, b.CATEGORY_ID FROM IMPORT_DOCUMENTS a JOIN (SELECT DISTINCT ITEMID FROM CATEGORY_COLLECTION_CATEGORY_RESULTS WHERE SCORE >= .7 AND SCORE <= .75 AND CATEGORY_ID IN (SELECT DISTINCT CATEGORY_ID FROM CATEGORY_COLLECTION_CATS WHERE COLLECTION_ID IN (11,16)) AND Sample_Id > 0) B ON a.ITEMID =b.ITEMID WHERE a.(a.BATCHID LIKE 'IC0%' OR a.BATCHID LIKE 'LP0%') AND a.ITEMID NOT IN (SELECT DIDTINCT Item_Id FROM ASSIGNMENT_FOLDER_DOCUMENTS)