How to use a select query results in an update query? - sqlite

I have two tables:
films(id,marksNum)
marks(id,film_id,mark)
I'd like to save number of marks for each film in films.marksNum.
My attempt is:
UPDATE films
SET marksNum=
(
SELECT count(id)
FROM marks
WHERE marks.film_id=films.id
GROUP BY marks.film_id
)
WHERE films.id=marks.film_id
but I'v got an error: no such column: marks.film_id
What am I doing wrong?
Thank you in advance!

Well, this is not an elegan solve but any way:
1)
CREATE TABLE `grp_marks` ( `film_id` INTEGER, `marks_num` INTEGER )
2)
INSERT INTO grp_marks(film_id,marks_num)
SELECT film_id,count(id)
FROM marks
GROUP BY film_id
3)
UPDATE films
SET marksNum=
(
SELECT marks_num
FROM grp_marks
WHERE (film_id=films.id)
)
WHERE EXISTS
(SELECT * FROM grp_marks WHERE grp_marks.film_id=films.id
)

Related

Error in concatenation of `LISTAGG` function[Not a duplicate question] [duplicate]

I have the following table TEMP
I want to create a pivot view using SQL, Ordered by CATEGORY ASC ,by LEVEL DESC and SET ASC and fill in the value .
Expected output:
I have tried the following code but unable to get a workaround the aggregate part which is throwing an error:
SELECT *
FROM
(SELECT
SET, LEVEL, CATEGORY, VALUE
FROM
TEMP
ORDER BY
CATEGORY ASC, LEVEL DESC, SET ASC) x
PIVOT
(value(VALUE) FOR RISK_LEVEL IN ('X','Y','Z') AND CATEGORY IN ('ABC', 'DEF', 'GHI', 'JKL')) p
Furthermore I want to know if there can be any method for dynamically adding the columns and arriving at this view for any table having the same columns (so that hardcoding can be avoided).
I know we can do this in Excel and transpose it, but I want the data to be stored in the db in this format.
A stored function(or procedure) might be created in order to create a SQL for Dynamic Pivoting, and the result set is loaded into a variable of type SYS_REFCURSOR :
CREATE OR REPLACE FUNCTION Get_Categories_RS RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols_1 VARCHAR2(32767);
v_cols_2 VARCHAR2(32767);
BEGIN
SELECT LISTAGG( ''''||"level"||''' AS "'||"level"||'"' , ',' )
WITHIN GROUP ( ORDER BY "level" DESC )
INTO v_cols_1
FROM (
SELECT DISTINCT "level"
FROM temp
);
SELECT LISTAGG( 'MAX(CASE WHEN category = '''||category||''' THEN "'||"level"||'" END) AS "'||"level"||'_'||category||'"' , ',' )
WITHIN GROUP ( ORDER BY category, "level" DESC )
INTO v_cols_2
FROM (
SELECT DISTINCT "level", category
FROM temp
);
v_sql :=
'SELECT "set", '|| v_cols_2 ||'
FROM
(
SELECT *
FROM temp
PIVOT
(
MAX(value) FOR "level" IN ( '|| v_cols_1 ||' )
)
)
GROUP BY "set"
ORDER BY "set"';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
in which I used two levels of pivoting : the first is within the inner query involving PIVOT Clause, and the second is in the outer query having the conditional aggregation logic. Notice that the order of levels should be in the descending order( Z, Y, X ) within the expected result as conforming to the description.
And then invoke
VAR rc REFCURSOR
EXEC :rc := Get_Categories_RS;
PRINT rc
from SQL Developer's Command Line in order to get the result set
Btw, avoid using reserved keywords such as set and level as in your case. I needed to quote them in order to be able to use.

reshape data in plsql [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I write a query which returns result like this :
but I should reshape result like below :
in fact, what I want is to track date and doc_no and qty for specific act_desc_, Can someone help me to rewrite query reshape in PL SQL? I would appreciate it if somebody can help me.
Since you've posted an image, i'll give you an example of how you can do it using some quick mock data, with SQL:
select ACT_DESC, MAX(EXCAVATION_QTY) as EXCAVATION_QTY, MAX(FORM_WORK_COMPLETION_QTY) as FORM_WORK_COMPLETION_QTY
from (
select QTY, ACT_DESC, TASK,
CASE WHEN TASK = 'EXCAVATION' THEN QTY ELSE NULL END as EXCAVATION_QTY,
CASE WHEN TASK = 'Form Work Completion' THEN QTY ELSE NULL END as FORM_WORK_COMPLETION_QTY
FROM
(
select 1 as QTY, 'a' as ACT_DESC, 'Excavation' as TASK
UNION ALL
select 2 as QTY, 'a' as ACT_DESC, 'Form Work Completion' as TASK
UNION ALL
select 11 as QTY, 'b' as ACT_DESC, 'Excavation' as TASK
UNION ALL
select 22 as QTY, 'b' as ACT_DESC, 'Form Work Completion' as TASK
) as t
) t1
GROUP BY ACT_DESC
It takes:
and converts it into:
/*
There are numerous complex queries that can be used, but here is a quick
and simple method that creates a base table first, then populates it after.
*/
--Step 1: Create empty base table with columns of the correct data type
CREATE TABLE BASE_TABLE AS
(
SELECT
ACT_DESC_,
QTY AS EXCAVATION_QTY,
APP_DATE AS EXCAVATION_APP_DATE,
DOC_NO AS EXCAVATION_DOC_NO,
QTY AS FORM_WORK_COMP_QTY,
APP_DATE AS FORM_WORK_COMP_APP_DATE,
DOC_NO AS FORM_WORK_COMP_DOC_NO,
FROM
SOURCE_TABLE --this is the original table, or the table from the first image
WHERE 0=1 --this clause condition is used to create an empty table
);
--Step 2: Insert into base table the unique ACT_DESC_ values
INSERT INTO BASE_TABLE
(
SELECT DISTINCT
ACT_DESC_
FROM
SOURCE_TABLE
);
--Using Merge statements
--Step 3: Update base table based on TASK_ = 'Excavation'
MERGE INTO BASE_TABLE TGT --Alias TGT short for TarGeT table
USING
(
SELECT * FROM SOURCE_TABLE
WHERE TASK_ = 'Excavaion'
) SRC --Alias SRC short for SouRCe table
ON ( TGT.ACT_DESC_ = SRC.ACT_DESC_ )
WHEN MATCHED THEN UPDATE
SET
TGT.EXCAVATION_QTY = SRC.QTY
TGT.EXCAVATION_APP_DATE = SRC.APP_DATE
TGT.EXCAVATION_DOC_NO = SRC.DOC_NO;
--Step 4: Update base table based on TASK_ = 'Form Work Completion'
MERGE INTO BASE_TABLE TGT --Alias TGT short for TarGeT table
USING
(
SELECT * FROM SOURCE_TABLE
WHERE TASK_ = 'Form Work Completion'
) SRC --Alias SRC short for SouRCe table
ON ( TGT.ACT_DESC_ = SRC.ACT_DESC_ )
WHEN MATCHED THEN UPDATE
SET
TGT.FORM_WORK_COMP_QTY = SRC.QTY
TGT.FORM_WORK_COMP_APP_DATE = SRC.APP_DATE
TGT.FORM_WORK_COMP_DOC_NO = SRC.DOC_NO;

Cannot replace a string with several random strings taken from another table in sqlite

I'm trying to replace a placeholder string inside a selection of 10 random records with a random string (a name) taken from another table, using only sqlite statements.
i've done a subquery in order to replace() of the placeholder with the results of a subquery. I thought that each subquery loaded a random name from the names table, but i've found that it's not the case and each placeholder is replaced with the same string.
select id, (replace (snippet, "%NAME%", (select
name from names
where gender = "male"
) )
) as snippet
from imagedata
where timestamp is not NULL
order by random()
limit 10
I was expecting for each row of the SELECT to have different random replacement every time the subquery is invoked.
hello i'm %NAME% and this is my house
This is the car of %NAME%, let me know what you think
instead each row has the same kind of replacement:
hello i'm david and this is my house
This is the car of david, let me know what you think
and so on...
I'm not sure it can be done inside sqlite or if i have to do it in php over two different database queries.
Thanks in advance!
Seems that random() in the subquery is only evaluated once.
Try this:
select
i.id,
replace(i.snippet, '%NAME%', n.name) snippet
from (
select
id,
snippet,
abs(random()) % (select count(*) from names where gender = 'male') + 1 num
from imagedata
where timestamp is not NULL
order by random() limit 10
) i inner join (
select
n.name,
(select count(*) from names where name < n.name and gender = 'male') + 1 num
from names n
where gender = 'male'
) n on n.num = i.num

record types that weren't found for a specific value in oracle query

I have this query
Select distinct p_id, p_date,p_city
from p_master
where p_a_id in(1,2,5,8,2,1,10,02)
and my IN clause contains 200 values. How do I get to know which ones weren't returned by the query. Each value in the IN clause may have a record in some cases they don't. I want to know all the records that weren't found for any selected p_a_id type.
Please help
This will do the trick but I'm sure there's an easier way to find this out :-)
with test1 as
(select '1,2,5,8,2,1,10,02' str from dual)
select * from (
select trim(x.column_value.extract('e/text()')) cols
from test1 t, table (xmlsequence(xmltype('<e><e>' || replace(t.str,',','</e><e>')|| '</e></e>').extract('e/e'))) x) cols
left outer join
(Select count(*), p_a_id from p_master where p_a_id in (1,2,5,8,2,1,10,02) group by p_a_id) p
on p.p_a_id = cols.cols
where p_a_id is null
;

SQL Select fields with a value of 'Y' and order by date descending, then select all others and order by another field ascending

I am generating an SQL query:
SELECT * FROM ToDoList
WHERE ws_status <> 'Completed'
AND (user_id= 'TESTUSR' OR ww_cover='TESTUSR'
OR (ws_status = 'Orphan' AND wwt_workgroupid IN (108)))
**ORDER BY psc_alt_code ASC**
And I need to list all results with wi_urgent set to 'Y' and order them by date Desc *first and then list all other results ordered by psc_alt_code descending* so I thought something like this would suffice:
ORDER BY (wi_urgent = 'Y') DESC, psc_alt_code ASC
I am getting SqlClient.SqlException: Incorrect syntax near '=' error when trying to run that query. Please note that I am querying an SQL View if that makes a difference?
You can use a case expression in the order by
SELECT * FROM ToDoList
WHERE ws_status <> 'Completed'
AND (user_id= 'TESTUSR' OR ww_cover='TESTUSR'
OR (ws_status = 'Orphan' AND wwt_workgroupid IN (108)))
ORDER BY CASE WHEN wi_urgent = 'Y' THEN 0 ELSE 1 END ASC
,psc_alt_code
I don't think you can do wi_urgent = 'Y' in an ORDER BY.
Since you're looking for all results with wi_urgent, try adding it to the WHERE clause:
SELECT * FROM ToDoList
WHERE ws_status <> 'Completed'
AND (user_id= 'TESTUSR' OR ww_cover='TESTUSR'
OR (ws_status = 'Orphan' AND wwt_workgroupid IN (108)))
AND wi_urgent = 'Y'
ORDER BY wi_urgent DESC,
psc_alt_code ASC

Resources