Reference table from subquery in Oracle - sql

I have simplified my tables but essentially I have a table of accounts that have a cycle_no and end date. This end date is always set to the first of the month but I need to get the real end date by looking in the calendar details table. The real end date is the next date for this cycle_no.
To create the simplified tables and enter a few rows of data:
CREATE TABLE DATA_OWNER.ACCOUNT
(
ACCNO NUMBER(4),
CYCLE_NO NUMBER(4),
ENDDATE DATE
);
CREATE TABLE DATA_OWNER.CALENDAR_DETAILS
(
CALENDAR_DT DATE,
BILL_CYCL_NO NUMBER(4)
);
INSERT INTO calendar_Details
VALUES
('18/DEC/2017',
17);
INSERT INTO calendar_Details
VALUES
('23/DEC/2017',
20);
INSERT INTO calendar_Details
VALUES
('18/JAN/2018',
17);
INSERT INTO calendar_Details
VALUES
('23/JAN/2018',
20);
INSERT INTO calendar_Details
VALUES
('20/FEB/2018',
17);
INSERT INTO calendar_Details
VALUES
('21/FEB/2018',
20);
INSERT INTO account
VALUES
(1, 17, '01/DEC/2107');
INSERT INTO account
VALUES
(2, 20, '01/DEC/2107');
If we run this query though we get "ACC". "ENDDATE": invalid identifier:
SELECT accno, cycle_no, enddate, actual_date
FROM account acc
JOIN
(
SELECT MIN(calendar_dt) actual_date
FROM calendar_details cal
WHERE calendar_dt > acc.enddate
)
ON acc.cycle_no = cal.bill_cycl_no;
Can anyone give us some pointers on the best way to achieve this please?

You cannot refer to outer table references in a subquery in the FROM. Just use a correlated subquery:
SELECT accno, cycle_no, enddate,
(SELECT MIN(cal.calendar_dt) as actual_date
FROM calendar_details cal
WHERE cal.calendar_dt > acc.enddate AND acc.cycle_no = cal.bill_cycl_no
) as actual_date
FROM account acc;

Related

How to insert value using a table in another table in postgres?

CREATE TABLE employee
(
joining_date date,
employee_type character varying,
name character varying
);
insert into employee VALUES
(NULL,'as','hjasghg'),
('2022-08-12', 'Rs', 'sa'),
(NULL,'asktyuk','hjasg');
create table insrt_st (employee_type varchar, dt date);
insert into insrt_st VALUES ('as', '2022-12-01'),('asktyuk', '2022-12-08')
What I want to do is write a single query to insert date from insrt_st in employee table where joining_date is null in employee column?
You can just write:
insert into employee (joining_date, employee_type, name) VALUES
(NULL,'as','hjasghg'),
('2022-08-12', 'Rs', 'sa'),
(NULL,'asktyuk','hjasg');
insert into insrt_st (employee_type, dt)
VALUES ('as', '2022-12-01')
,('asktyuk', '2022-12-08') ;
UPDATE employee
SET joining_date = I.dt
FROM insrt_st I
WHERE employee.employee_type = I.employee_type
AND employee.joining_date IS NULL;
SELECT joining_date,employee_type,name
FROM employee
Here is example.

Insert grouped data

I am getting expected results from my query, I am using group by to group the data on the basis of different Ids.
The problem I am facing is that I have to insert this grouped data in the table called gstl_calculated_daily_fee, but when I pass the grouped result to variables called #total_mada_local_switch_high_value and #mada_range_id and insert them in the table then I get only the last result of the query in the table.
Sample result:
Fee range_id
1.23 1
1.22 2
2.33 3
I get only 2.33 and 1 after I insert but I have to insert the whole result in to the table.
Please suggest how can I insert the whole query result into the table. Below is the query:
DECLARE #total_mada_local_switch_high_value decimal(32,4) = 0.00;
DECLARE #mada_range_id int = 0;
select
#total_mada_local_switch_high_value = SUM(C.settlement_fees),
#mada_range_id = C.range_id
From
(
select
*
from
(
select
rowNumber = #previous_mada_switch_fee_volume_based_count + (ROW_NUMBER() OVER(PARTITION BY DATEPART(MONTH, x_datetime) ORDER BY x_datetime)),
tt.x_datetime
from gstl_trans_temp tt where (message_type_mapping = 0220) and card_type ='GEIDP1' and response_code IN(00,10,11) and tran_amount_req >= 5000
) A
CROSS APPLY
(
select
rtt.settlement_fees,
rtt.range_id
From gstl_mada_local_switch_fee_volume_based rtt
where A.rowNumber >= rtt.range_start
AND (A.rowNumber <= rtt.range_end OR rtt.range_end IS NULL)
) B
) C
group by CAST(C.x_datetime AS DATE),C.range_id
-- Insert Daily Volume
INSERT INTO
gstl_calculated_daily_fee(business_date,fee_type,fee_total,range_id)
VALUES
(#tlf_business_date,'MADA_SWITCH_FEE_LOCAL_CARD', #total_mada_local_switch_high_value, #mada_range_id)
I see no need for variables here. You can insert the aggregated results directly.
Sample data
create table Data
(
Range int,
Fee money
);
insert into Data (Range, Fee) values
(1, 1.00),
(1, 0.50),
(2, 3.00),
(3, 0.25),
(3, 0.50);
create table DataSum
(
Range int,
FeeSum money
);
Solution
insert into DataSum (Range, FeeSum)
select d.Range, sum(d.Fee)
from Data d
group by d.Range;
Fiddle to see things in action.

have multiple columns need to display column type with other column in rows

input
enter image description here
output
enter image description here
select deptno, replace(title,'d','author),date from employee
for the particular departno I have multiple title and date so i want to display in row wise example
Your data does not match your desired results. Here is what I believe you want:
create table deleteme_tbl(department int, title varchar2(20), mydate date);
insert into deleteme_tbl values( 1,'One', date '2016-01-01');
insert into deleteme_tbl values( 1,'Two', date '2016-04-01');
insert into deleteme_tbl values( 1,'three', date '2016-02-02');
insert into deleteme_tbl values( 2,'five', date '2016-04-04');
insert into deleteme_tbl values( 2,'six', null);
insert into deleteme_tbl values( 2,'seven', null);
commit;
SELECT department
, LISTAGG (title, ',') WITHIN GROUP (ORDER BY title) titles
, LISTAGG (mydate, ',') WITHIN GROUP (ORDER BY mydate) mydates
FROM deleteme_tbl
GROUP BY department;
DEPARTMENT TITLES MYDATES
1 One,Two,three 01-JAN-16,02-FEB-16,01-APR-16
2 five,seven,six 04-APR-16

Oracle SQL invalid identifier error in nested WITH subquery

Below you will find three sample tables and data along with a query. This example might seem contrived, but it is part of much larger (nearly 1500 lines) SQL query. The original query works great, but I've run into a problem while adding some new functionality.
CREATE TABLE rule_table (
id_rule_table NUMBER (10),
name VARCHAR2 (24),
goal NUMBER (10),
amount NUMBER (10)
);
INSERT INTO rule_table (id_rule_table, name, goal, amount) VALUES(1, 'lorem', 2, 3);
INSERT INTO rule_table (id_rule_table, name, goal, amount) VALUES(2, 'ipsum', 3, 3);
INSERT INTO rule_table (id_rule_table, name, goal, amount) VALUES(3, 'dolor', 4, 3);
CREATE TABLE content_table (
id_content_table NUMBER (10),
name VARCHAR2 (24),
show_flag NUMBER (10)
);
INSERT INTO content_table (id_content_table, name, show_flag) VALUES(1, 'lorem', 0);
INSERT INTO content_table (id_content_table, name, show_flag) VALUES(2, 'ipsum', 1);
INSERT INTO content_table (id_content_table, name, show_flag) VALUES(3, 'dolor', 1);
CREATE TABLE module_table (
id_module_table NUMBER (10),
id_content_table NUMBER (10),
name VARCHAR2 (24),
amount NUMBER (10)
);
INSERT INTO module_table (id_module_table, id_content_table, name, amount) VALUES(1, 2, 'lorem', 10);
INSERT INTO module_table (id_module_table, id_content_table, name, amount) VALUES(2, 2, 'ipsum', 11);
INSERT INTO module_table (id_module_table, id_content_table, name, amount) VALUES(3, 2, 'dolor', 12);
SELECT RULE.id_rule_table
FROM rule_table RULE
WHERE (
CASE
WHEN RULE.goal <= (
WITH contentTbl (id_content_table)
AS (
SELECT id_content_table
FROM content_table
WHERE show_flag = 1
),
modulesTbl (id_content_table, id_module_table)
AS (
SELECT C.id_content_table, M.id_module_table
FROM contentTbl C
JOIN module_table M ON M.id_content_table = C.id_content_table
WHERE 4 < M.amount - RULE.amount
)
SELECT SUM(M.id_module_table)
FROM contentTbl C
JOIN modulesTbl M ON C.id_content_table = M.id_content_table
)
THEN 1
ELSE 0
END
) = 1;
DROP TABLE rule_table;
DROP TABLE content_table;
DROP TABLE module_table;
If you try this you will receive the error ORA-00904: "RULE"."AMOUNT": invalid identifier. The problem lies with the line "WHERE 4 < M.amount - RULE.amount".
If you replace RULE.amount, in that line, with some number (e.g., WHERE 4 < M.amount - 3) then the query will run just fine.
As mentioned above, this is a snippet test case from a much larger query, so the structure of the query can't be (or hopefully doesn't need to be) changed too much. That is, ideally I'm looking for a solution that will allow me to use RULE.amount in the sub-query without changing anything other that the SQL inside of the "WHEN RULE.goal <= ()" block.
I'm trying to run this on Oracle 11g.
One last thing, I tried searching google and stackoverflow for solutions, but I couldn't figure out the correct terminology to describe my issue. The closest thing seemed to be nested correlated subquery, but that doesn't seem to be exactly right.
Taking into account that this is only part of a much larger query, here are the surgical changes required to make this work:
Move the WHERE 4 < M.amount - RULE.amount condition out of the CTE and into the main query so that RULE is in scope.
Modify the modulesTbl CTE to return an additional column amount so that M.amount is now available to the main query.
With these 2 changes, the query would look like this:
SELECT RULE.id_rule_table
FROM rule_table RULE
WHERE (
CASE
WHEN RULE.goal <= (
WITH contentTbl (id_content_table)
AS (
SELECT id_content_table
FROM content_table
WHERE show_flag = 1
),
modulesTbl (id_content_table, id_module_table, amount) -- add amount
AS (
SELECT C.id_content_table, M.id_module_table, M.amount -- add amount
FROM contentTbl C
JOIN module_table M ON M.id_content_table = C.id_content_table
)
SELECT SUM(M.id_module_table)
FROM contentTbl C
JOIN modulesTbl M ON C.id_content_table = M.id_content_table
AND 4 < M.amount - RULE.amount -- moved from CTE to here
)
THEN 1
ELSE 0
END
) = 1;

SQLite: Update one column based on a condition set in another table

I'm a total noob in SQL and I've only just begun working with SQLite, and this is my first post here, so please pardon my inherent lack of understanding. I've been self-teaching myself after graduating with a BA, so please bear with me lol.
I've managed to get the following query to work, but only if all of the data was a part of the same table. I've since broken my two tables into three separate tables: widgetCustomer, widgetSale, and widgetOrderInfo.
UPDATE widgetOrderInfo
SET extendedcost = (cost * qty) * (0.80)
WHERE widgetCustomer.IsASenior = 'Y';
-- Seniors get a 20 percent discount;
^^ This is the part I'm having trouble with. Whenever I use this query SQLite returns, "No such column: IsASenior."
--NOTE: IsASenior is a column in widgetCustomer set to either 'Y' or 'N' based on a trigger earlier on in the code. I've gotten base multiplication to work very easily using only the data in the widgetOrderInfo table using the following query:
UPDATE widgetOrderInfo
SET extendedcost = (cost * qty);
Very basic, I'm aware, but I'm unsure what I must do in order to get my widgetOrderInfo table to acknowledge the data in widgetCustomer's 'IsASenior' column.
Do I have to use a JOIN in order to access data between two tables in an UPDATE statement?
Any assistance would be great! Thanks!
FULL LIST AND ORDER OF QUERIES I'M CURRENTLY PERFORMING (Lots of place-holders; WIP)
CREATE TABLE widgetCustomer
( id INTEGER PRIMARY KEY, name TEXT, age INT, IsASenior TEXT, last_order_id INT, soItemID INT );
CREATE TABLE widgetSale
( id INTEGER PRIMARY KEY, item_id INT, item_name TEXT, customer_id INT, quan INT, price MONEY(8,2) );
CREATE TABLE widgetOrderInfo
( id INTEGER PRIMARY KEY, salesOrderID INT, cost MONEY(8,2), qty INT, extendedcost MONEY(8,2) )
;
CREATE TRIGGER SeniorCheck AFTER INSERT ON widgetCustomer
BEGIN
UPDATE widgetCustomer
SET IsASenior = 'Y' WHERE age >= 65;
UPDATE widgetCustomer
SET IsASenior = 'N' WHERE age < 65;
END
;
INSERT INTO widgetCustomer (name, age, soItemID)
VALUES ('Ian', 24, 3);
INSERT INTO widgetCustomer (name, age, soItemID)
VALUES ('Andrew', 29, 2);
INSERT INTO widgetCustomer (name, age, soItemID)
VALUES ('John', 65, 1);
INSERT INTO widgetCustomer (name, age, soItemID)
VALUES ('Kathy', 60, 4)
;
CREATE TRIGGER newWidgetSale AFTER INSERT ON widgetSale
BEGIN
UPDATE widgetCustomer
SET last_order_id = NEW.id
WHERE widgetCustomer.id = NEW.customer_id;
END
;
INSERT INTO widgetSale (item_id, item_name, customer_id, quan, price)
VALUES (1, 'Blue Brick', 3, 50, 9.95);
INSERT INTO widgetSale (item_id, item_name, customer_id, quan, price)
VALUES (2, 'Red Brick', 2, 30, 4.95);
INSERT INTO widgetSale (item_id, item_name, customer_id, quan, price)
VALUES (3, 'Black Brick', 1, 24, 9.95);
INSERT INTO widgetSale (item_id, item_name, customer_id, quan, price)
VALUES (4, 'Yellow Brick', 4, 30, 9.95)
;
CREATE TRIGGER SubtractQuan AFTER INSERT ON widgetOrderInfo FOR EACH ROW
BEGIN
UPDATE widgetSale
SET quan = (quan - New.qty)
WHERE customer_id = New.id;
END
;
INSERT INTO widgetOrderInfo (salesOrderID, cost, qty)
VALUES (283001, 9.95, 4);
INSERT INTO widgetOrderInfo (salesOrderID, cost, qty)
VALUES (283002, 4.95, 8);
INSERT INTO widgetOrderInfo (salesOrderID, cost, qty)
VALUES (283003, 9.95, 5);
INSERT INTO widgetOrderInfo (salesOrderID, cost, qty)
VALUES (283004, 9.95, 15)
;
UPDATE widgetOrderInfo
SET extendedcost = (cost * qty)
;
SELECT
CASE
WHEN qty BETWEEN 5 and 7 THEN 'parcel'
WHEN qty BETWEEN 8 and 14 THEN 'package'
WHEN qty BETWEEN 15 and 30 THEN 'box'
WHEN qty BETWEEN 31 and 99 THEN 'crate'
ELSE 'individually wrapped'
END
AS PackagingBasedOnPurchaseSize,
COUNT(*) qty FROM widgetOrderInfo
GROUP BY
CASE
WHEN qty BETWEEN 5 and 7 THEN 'parcel'
WHEN qty BETWEEN 8 and 14 THEN 'package'
WHEN qty BETWEEN 15 and 30 THEN 'box'
WHEN qty BETWEEN 31 and 99 THEN 'crate'
ELSE 'individually wrapped'
END
;
SELECT * FROM widgetSale;
SELECT * FROM widgetCustomer;
SELECT * FROM widgetOrderInfo;
I can provide a link to my whole database if need be.
In an UPDATE statement, you can directly access only the updated table itself.
To access other tables, you need a subquery.
To find order info rows associated with senior customers, you can either look up the corresponding customer row for each order info row with a correlated subquery:
UPDATE widgetOrderInfo
SET extendedcost = (cost * qty) * (0.80)
WHERE (SELECT IsASenior
FROM widgetCustomer
JOIN widgetSale ON widgetCustomer.id = widgetSale.customer_id
WHERE widgetSale.id = widgetOrderInfo.salesOrderID
) = 'Y';
Or get all senior customers first, and check which order infos are in that set:
UPDATE widgetOrderInfo
SET extendedcost = (cost * qty) * (0.80)
WHERE salesOrderID IN (SELECT widgetSale.id
FROM widgetCustomer
JOIN widgetSale ON widgetCustomer.id = widgetSale.customer_id
WHERE IsASenior = 'Y');