Access top query column from subquery in SQL - sql

In my subquery I want to access the columns of the upper query to perform a coalesce. This is obviously not possible, but how can I manipulate my query to make it work? I am out of ideas.
WITH selected_students AS
(
SELECT amka, course_code
FROM "Register"
WHERE EXISTS (SELECT course_code FROM "CourseRun"
WHERE semesterrunsin = 24
AND course_code = "Register".course_code
AND serial_number = "Register".serial_number)
)
SELECT
amka, course_code,
FLOOR(RANDOM()*11) :: numeric,
COALESCE((SELECT lab_grade
FROM
(SELECT lab_grade FROM "Register_tmp"
WHERE "Register_tmp".amka = <outer.amka>
AND course_code = <outer.course_code>
AND serial_number < 12
ORDER BY serial_number DESC
LIMIT(1)) a
WHERE lab_grade >= 5), FLOOR(RANDOM()*11) :: numeric)
FROM
selected_students

Related

How to insert into return table values if no value is found from select

I have current function
CREATE OR REPLACE FUNCTION G_test(
i_tag_id integer,
timestamp_from timestamp,
timestamp_to timestamp
)
returns table (
o_value kepware_messages.value%type,
tag_id integer,
created_at timestamp
)
language plpgsql
as $$
begin
return query
(SELECT kepware_messages.value, kepware_messages.tag_id,kepware_messages.created_at FROM kepware_messages where kepware_messages.tag_id = i_tag_id and kepware_messages.created_at>=timestamp_from and kepware_messages.created_at<=timestamp_to)
UNION
(SELECT kepware_messages.value, kepware_messages.tag_id, kepware_messages.created_at FROM kepware_messages where kepware_messages.tag_id = i_tag_id and kepware_messages.created_at<timestamp_from ORDER BY kepware_messages.created_at DESC LIMIT 1)
UNION
(SELECT kepware_messages.value, kepware_messages.tag_id, kepware_messages.created_at FROM kepware_messages where kepware_messages.tag_id = i_tag_id and kepware_messages.created_at>timestamp_to ORDER BY kepware_messages.created_at ASC LIMIT 1)
ORDER BY created_at DESC;
end;$$
I would like to do the following if in third select from union no table entry is found, to enter my own values.
In such case I would enter
o_value = 'false';
tag_id = i_tag_id;
created_at = timestamp_from;
With help of google I found that you can use
if not found then
Though I am not yet sure how to implement it into union, however I can not find how to insert your own row of data into return table.
Also shouldn't this function return a different kind of table? It looks to me like everything is in same column.
https://i.ibb.co/tMwnXQ2/1.jpg
Sorry, I can't post images yet.
Return a row from the table or a constructed row if no requested rows exist in the table.
SELECT t.value, t.tag_id, t.created_at
FROM
(SELECT 1 rn, km.value, km.tag_id, km.created_at
FROM kepware_messages km
WHERE km.tag_id = i_tag_id and km.created_at>timestamp_to
ORDER BY km.created_at ASC
LIMIT 1
UNION ALL
SELECT 2 rn, 'false' value, i_tag_id tag_id , timestamp_from created_at
) t
ORDER BY rn
LIMIT 1
Replace the third select from your union with this one.

How to filter out NULLs from a window function

I'm trying to return just non-null diff_review values > 1 and so far this has been my result:
This is the query that generated this:
select review_number
, review_number - lag(review_number, 1) over (partition by organization_id order by review_number) as diff_review from applications
where organization_id = 25144
and kind = 'annual_review'
and review_number is not null
order by diff_review desc
I can't use ...and diff_review is not null since you can't use aliases in where clauses, but I found out today you also can't use windowing functions in where clauses either.
This is the first time I've ever used windowing in SQL (I hadn't even heard of it until an hour ago) so I'm still very green at this. I'd appreciate someone clueing me in thanks!!!
You can use a table expression to "alias" the column. For example:
select *
from (
select review_number
, review_number - lag(review_number, 1)
over (partition by organization_id order by review_number)
as diff_review
from applications
where organization_id = 25144
and kind = 'annual_review'
and review_number is not null
) x
where diff_review is not null -- here you can use the aliased column
order by diff_review desc
Alternative method: a self join on row_number():
with omg AS (
select review_number
, row_number() over (partition by organization_id order by review_number) as rn
from applications
where organization_id = 25144
and kind = 'annual_review'
)
SELECT o2.review_number
, o2.review_number - o1.review_number AS diff_review
FROM omg o2
JOIN omg o1 ON (o2.review_number = o1.review_number AND o2.rn = o1.rn +1)
order by 2 desc
;

HPE Vertica live aggregate projection example for user retention

create table events(
id char(36) PRIMARY KEY,
game_id varchar(24) not null,
user_device_id char(36) not null,
event_name varchar(100) not null,
generated_at timestamp with time zone not null
);
SELECT
events.generated_at::DATE AS time_stamp,
COUNT(DISTINCT (
CASE WHEN
events.event_name = 'new_user' THEN events.user_device_id
END
)
) as new_users,
COUNT(DISTINCT (
CASE WHEN
future_events.event_name <> 'new_user' THEN future_events.user_device_id
END
)
) as returned_users,
COUNT(DISTINCT (
CASE WHEN
future_events.event_name <> 'new_user' THEN future_events.user_device_id
END
)) / COUNT(DISTINCT (
CASE WHEN
events.event_name = 'new_user' THEN events.user_device_id
END
))::float as retention
FROM events
LEFT JOIN events AS future_events ON
events.user_device_id = future_events.user_device_id AND
events.generated_at = future_events.generated_at - interval '1 day' AND
events.game_id = future_events.game_id
GROUP BY
time_stamp
ORDER BY
time_stamp;
I am trying to get the Day N ('N' -> any number between 1 to 7) user retention via the above sql query. Due to the fact that I am a noob in HPE vertica, I am not being able to come up the optimum aggregate projection creating statement, Since projection significantly improves the performance of the query.
Aggregated projection won't help with a join query.
You can create a regular projection, segmented and sorted by the join columns, to achieve performance improvement:
CREATE PROJECTION events_p1 (
id,
game_id ENCODING RLE,
user_device_id ENCODING RLE,
event_name,
generated_at ENCODING RLE
) AS
SELECT id,
game_id,
user_device_id,
event_name,
generated_at
FROM events
ORDER BY generated_at,
game_id,
user_device_id
SEGMENTED BY hash(generated_at,game_id,user_device_id) ALL NODES KSAFE 1;

ROW_NUMBER() Query Plan SORT Optimization

The query below accesses the Votes table that contains over 30 million rows. The result set is then selected from using WHERE n = 1. In the query plan, the SORT operation in the ROW_NUMBER() windowed function is 95% of the query's cost and it is taking over 6 minutes to complete execution.
I already have an index on same_voter, eid, country include vid, nid, sid, vote, time_stamp, new to cover the where clause.
Is the most efficient way to correct this to add an index on vid, nid, sid, new DESC, time_stamp DESC or is there an alternative to using the ROW_NUMBER() function for this to achieve the same results in a more efficient manner?
SELECT v.vid, v.nid, v.sid, v.vote, v.time_stamp, v.new, v.eid,
ROW_NUMBER() OVER (
PARTITION BY v.vid, v.nid, v.sid ORDER BY v.new DESC, v.time_stamp DESC) AS n
FROM dbo.Votes v
WHERE v.same_voter <> 1
AND v.eid <= #EId
AND v.eid > (#EId - 5)
AND v.country = #Country
One possible alternative to using ROW_NUMBER():
SELECT
V.vid,
V.nid,
V.sid,
V.vote,
V.time_stamp,
V.new,
V.eid
FROM
dbo.Votes V
LEFT OUTER JOIN dbo.Votes V2 ON
V2.vid = V.vid AND
V2.nid = V.nid AND
V2.sid = V.sid AND
V2.same_voter <> 1 AND
V2.eid <= #EId AND
V2.eid > (#EId - 5) AND
V2.country = #Country AND
(V2.new > V.new OR (V2.new = V.new AND V2.time_stamp > V.time_stamp))
WHERE
V.same_voter <> 1 AND
V.eid <= #EId AND
V.eid > (#EId - 5) AND
V.country = #Country AND
V2.vid IS NULL
The query basically says to get all rows matching your criteria, then join to any other rows that match the same criteria, but which would be ranked higher for the partition based on the new and time_stamp columns. If none are found then this must be the row that you want (it's ranked highest) and if none are found that means that V2.vid will be NULL. I'm assuming that vid otherwise can never be NULL. If it's a NULLable column in your table then you'll need to adjust that last line of the query.

ORACLE SQL equivalent to given mysql query

Hi I am stuck on conerting this query from mysql to oracle as oracle create problems in subquery order by. Query is:
SELECT bt_charges.bt_setup_id, bt_setups.name, IFNULL(bt_charges.charges_for,'OPD') as charges_for_vals, bt_charges.nc_applicable,bt_charges.unit_value,bt_charges.taxtype_id, bt_charges.id, bt_charges.amount, bt_charges.effective_date
FROM bt_setups JOIN bt_charges ON ( bt_charges.bt_setup_id = bt_setups.id AND
bt_charges.id = (SELECT id
FROM bt_charges ilaba
WHERE IFNULL(ilaba.charges_for,'OPD') = IFNULL(bt_charges.charges_for,'OPD')
AND ilaba.bt_setup_id= bt_setups.id AND ilaba.effective_date <= '2014-11-10'
AND ilaba.insprovider_id IS NULL AND ilaba.deleted=0
ORDER BY ilaba.effective_date DESC, ilaba.date_entered DESC
LIMIT 1))
WHERE bt_setups.status='Active' AND bt_setups.deleted=0
AND bt_charges.insprovider_id IS NULL
ORDER BY bt_setups.name, charges_for ASC
Here, bt_setups ( name, description ) is service provided and
bt_charges (effective_date date, date_entered datetime, charger_for char, bt_setup_id foreign key(bt_setups), insprovider_id foreign key(insproviders) ) contains charges for service applicable from effective_date, insprovider wise
SELECT bc.bt_setup_id, bs.name,
NVL(bc.charges_for,'OPD') as charges_for_vals,
bc.nc_applicable, bc.unit_value, bc.taxtype_id,
bc.id, bc.amount, bc.effective_date
FROM bt_setups bs JOIN bt_charges bc ON ( bc.bt_setup_id = bs.id AND
bc.id = (SELECT id FROM
(SELECT ilaba.id, ilaba.bt_setup_id
FROM bt_charges ilaba
WHERE NVL(ilaba.charges_for,'OPD') = NVL(bc.charges_for,'OPD')
AND ilaba.effective_date <= TO_DATE('2014-11-10', 'YYYY-MM-DD')
AND ilaba.insprovider_id IS NULL AND ilaba.deleted=0
ORDER BY ilaba.effective_date DESC, ilaba.date_entered DESC)
WHERE bt_setup_id = bs.id AND ROWNUM = 1
))
WHERE bs.status='Active' AND bs.deleted=0
AND bc.insprovider_id IS NULL
ORDER BY bs.name, charges_for ASC;
IFNULL -> NVL
'2014-11-10' -> TO_DATE('2014-11-10', 'YYYY-MM-DD') - I suppose ilaba.effective_date has DATE type
LIMIT 1 -> order by in the subquery + rownum=1 in the parent query