Why it is showing No such column - sql

/* Triggers*/
create table acustomer( id integer primary key, desc text, last_order_id integer);
create table bcustomer ( id integer primary key, item_id int, customer_id int, quan int, price int);
insert into acustomer (desc) values ( 'rohan');
insert into acustomer (desc) values ('mohan');
insert into acustomer (desc) values ('sohan');
select * from acustomer;
create trigger ccustomer after insert on bcustomer
begin
update acustomer set last_order_id = NEW.id where acustomer.id = NEW.customer_id;
end;
insert into bcustomer (item_id, customer_id, quan, price) values (1, 2, 3, 4);
insert into bcustomer (item_id, customer_id, quan, price) values (5, 6, 7, 8);
insert into bcustomer (item_id, customer_id, quan, price) values (8, 9, 10, 20);
insert into bcustomer (item_id, customer_id, quan, price) values (4, 12, 19, 13);
select * from acustomer;
select * from bcustomer;
#On executing insertion in table ccustomer, it is showing error : no such column : NEW.customer.id

Your last insert for bcustomer table is
insert into bcustomer (item_id, customer_id, quan, price) values (4, 12, 19, 13);
which doesn't have any matching last_order_id in acustomer.
If you will run
insert into bcustomer (item_id, customer_id, quan, price) values (4, 1, 19, 13);
customer_id = 1, it will update your acustomer table since it has a matching id, which is 1.
try this dbfiddle.

Related

Find all records in a table where the most recent record in a join table has a column which is not equal to one is this table?

Image the tables:
CREATE TABLE items (
id INT,
price INT
);
CREATE TABLE item_price_history (
id INT,
item_id INT,
price INT
);
With the following data:
INSERT INTO items (id, price) VALUES (1, 199);
INSERT INTO items (id, price) VALUES (2, 159);
INSERT INTO items (id, price) VALUES (3, 129);
INSERT INTO items (id, price) VALUES (4, 119);
INSERT INTO item_price_history (id, item_id, price) VALUES (1, 1, 249);
INSERT INTO item_price_history (id, item_id, price) VALUES (2, 1, 239);
INSERT INTO item_price_history (id, item_id, price) VALUES (3, 1, 229);
INSERT INTO item_price_history (id, item_id, price) VALUES (4, 1, 199);
INSERT INTO item_price_history (id, item_id, price) VALUES (5, 2, 299);
INSERT INTO item_price_history (id, item_id, price) VALUES (6, 2, 259);
INSERT INTO item_price_history (id, item_id, price) VALUES (7, 2, 159);
INSERT INTO item_price_history (id, item_id, price) VALUES (8, 2, 109);
INSERT INTO item_price_history (id, item_id, price) VALUES (9, 3, 129);
INSERT INTO item_price_history (id, item_id, price) VALUES (10, 4, 159);
INSERT INTO item_price_history (id, item_id, price) VALUES (11, 4, 119);
INSERT INTO item_price_history (id, item_id, price) VALUES (13, 4, 99);
Now I would like to find all the items for which the items.price is not equal to the most recent item_price_history.price (id DESC) in item_price_history. In this case that should produce item with id 3 and 4. As their prices does NOT match the most recent price in item_price_history.
I did the following which works:
SELECT items.id, items.price i_price, item_price_history.id, item_price_history.price as ih_price
FROM items
LEFT JOIN item_price_history ON item_price_history.item_id = items.id
AND item_price_history.id = (SELECT MAX(id) FROM item_price_history WHERE item_id = items.id)
WHERE items.price != item_price_history.price
LIMIT 100
However I have a table of about 2 million rows in items and 20 million rows in item_price_history which I need to scan through, so performance is important.
How would I write such a query in a more performant way e.g by using DISTINCT ON or something?
https://www.db-fiddle.com/f/wPkdHvvzS2tmZq2vKUwgNi/2
Here is a query to do it in bulk with DISTINCT ON:
SELECT items.id, items.price i_price, item_price_history.id, item_price_history.price as ih_price
from items
join (select distinct on (item_id) id, item_id, price from item_price_history order by item_id desc, id desc) item_price_history
on item_price_history.item_id = items.id
WHERE items.price != item_price_history.price;
It should be well supported by an index on item_price_history (item_id , id, price); which will let it do a presorted index-only scan.

Can I reference this table?

I am trying to show amount paid for each tutor sorted by month and then by tutor id. I have the first part correct and can sort by month but cannot sort by tutor id because it is from a different table.
Here is the script for my tables:
create table match_history
(match_id number(3),
tutor_id number(3),
student_id number(4),
start_date date,
end_date date,
constraint pk_match_history primary key (match_id),
constraint fk1_match_history foreign key (tutor_id) references tutor(tutor_id),
constraint fk2_match_history foreign key (student_id) references student(student_id));
create table tutor_report
(match_id number(3),
month date,
hours number(3),
lessons number(3),
constraint pk_tutor_report primary key (match_id, month),
constraint fk1_tutor_report foreign key (match_id) references match_history(match_id));
insert into tutor values (100, '05-JAN-2017', 'Active');
insert into tutor values (101, '05-JAN-2017', 'Temp Stop');
insert into tutor values (102, '05-JAN-2017', 'Dropped');
insert into tutor values (103, '22-MAY-2017', 'Active');
insert into tutor values (104, '22-MAY-2017', 'Active');
insert into tutor values (105, '22-MAY-2017', 'Temp Stop');
insert into tutor values (106, '22-MAY-2017', 'Active');
insert into student values (3000, 2.3);
insert into student values (3001, 5.6);
insert into student values (3002, 1.3);
insert into student values (3003, 3.3);
insert into student values (3004, 2.7);
insert into student values (3005, 4.8);
insert into student values (3006, 7.8);
insert into student values (3007, 1.5);
insert into match_history values (1, 100, 3000, '10-JAN-2017', null);
insert into match_history values (2, 101, 3001, '15-JAN-2017', '15-MAY-2017');
insert into match_history values (3, 102, 3002, '10-FEB-2017', '01-MAR-2017');
insert into match_history values (4, 106, 3003, '28-MAY-2017', null);
insert into match_history values (5, 103, 3004, '01-JUN-2017', '15-JUN-2017');
insert into match_history values (6, 104, 3005, '01-JUN-2017', '28-JUN-2017');
insert into match_history values (7, 104, 3006, '01-JUN-2017', null);
insert into tutor_report values (1, '01-JUN-2017', 8, 4);
insert into tutor_report values (4, '01-JUN-2017', 8, 6);
insert into tutor_report values (5, '01-JUN-2017', 4, 4);
insert into tutor_report values (4, '01-JUL-2017', 10, 5);
insert into tutor_report values (1, '01-JUL-2017', 4, 2);
This is what I have so far:
Select (hours * 10) as amount paid from tutor_report group by month, tutor_id
however obviously I cannot just say tutor_id at the end.
You can join match_history to get the tutor_id.
But your statement and the query don't match. If you want to sort use ORDER BY.
SELECT tr.hours * 10 amount_paid
FROM tutor_report tr
INNER JOIN match_history mh
ON mh.match_id = tr.match_id
ORDER BY tr.month,
mh.tutor_id;
If you want to aggregate, hours needs to be argument to some aggregation function. Maybe you're after the sum of hours?
SELECT sum(tr.hours) * 10 amount_paid
FROM tutor_report tr
INNER JOIN match_history mh
ON mh.match_id = tr.match_id
GROUP BY tr.month,
mh.tutor_id;
If you are grouping based on columns on two tables,you need to join them on the matching Id and then use group by
Select (hours * 10) as amount paid
from tutor_report a
join match_history b on a. match_id = b.match_id
group by month, tutor_id

Is there any function for insert more than one row with trigger group by some result?

CREATE TABLE TABLE_1 (
ID NUMBER(10),
ID_DOCUMENT NUMBER(10),
ITEM_ID NUMBER(10),
SUPLLIER NUMBER(10)
);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (1, 1, 11, 25);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (2, 1, 87, 31);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (3, 1, 93, 31);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (4, 1, 41, 25);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (5, 1, 58, 40);
When I insert into table_1 I have to insert the result into two other tables:
create table doc
(
id number(10),
suplier number(10),
date_doc date
);
create table doc_rows
(
id number(10),
id_doc number(10), -- (references doc.id)
item_id number(10)
);
I want to create 3 new records in table doc (because into table_1 we have 3 unique suppliers) and for every new doc I have to insert his items into table doc_rows
-- Create tables
CREATE TABLE TABLE_1 (
ID int identity (1,1) ,
ID_DOCUMENT int,
ITEM_ID int,
SUPLLIER int
);
create table doc
(
id int identity (1,1),
suplier int,
date_doc date
);
create table doc_rows
(
id int identity (1,1),
id_doc int, -- (references doc.id)
item_id int
);
--Create triggers
GO
CREATE TRIGGER trgTABLE_1_Insert ON TABLE_1
FOR INSERT
AS
declare #SUPLLIER int
select #SUPLLIER = SUPLLIER from inserted
if not exists (select 1 from doc where suplier=#SUPLLIER )
Begin
insert into doc (suplier,date_doc)
select #SUPLLIER,GETDATE()
insert into doc_rows (id_doc,item_id)
SELECT (select id from doc where suplier = #SUPLLIER) id_doc ,
(SELECT top 1 ITEM_ID from TABLE_1 where SUPLLIER = #SUPLLIER) item_id
End
Go
-- insert statement
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 11, 25);
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 87, 31);
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 93, 31);
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 41, 25);
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 58, 40);
--fianl output
SELECT * from TABLE_1
SELECT * from doc
SELECT * from doc_rows

Update / Merge table with summing values

I have a schema:
http://sqlfiddle.com/#!4/e9917/1
CREATE TABLE test_table (
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO test_table VALUES (1000, 1, 100);
INSERT INTO test_table VALUES (1000, 1, 500);
INSERT INTO test_table VALUES (1001, 1, 200);
INSERT INTO test_table VALUES (1001, 2, 300);
INSERT INTO test_table VALUES (1002, 1, 900);
INSERT INTO test_table VALUES (1002, 1, 250);
I want to update the amount field by adding amounts of records which has same (id, period) pair. like after op :
ID| period| amount
1000 1 600
1001 1 200
1001 2 300
1002 1 1150
I Couldn't figure out how :(
EDIT:
In actual case this table is populated by insertion operation from other 2 tables:
CREATE TABLE some_table1(
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO some_table1 VALUES (1000, 1, 100);
INSERT INTO some_table1 VALUES (1000, 1, 500);
INSERT INTO some_table1 VALUES (1001, 1, 200);
INSERT INTO some_table1 VALUES (1001, 2, 300);
INSERT INTO some_table1 VALUES (1002, 1, 900);
INSERT INTO some_table1 VALUES (1002, 1, 250);
CREATE TABLE some_table2(
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO some_table2 VALUES (1000, 1, 30);
INSERT INTO some_table2 VALUES (1000, 1, 20);
INSERT INTO some_table2 VALUES (1001, 1, 15);
INSERT INTO some_table2 VALUES (1001, 2, 20);
INSERT INTO some_table2 VALUES (1002, 1, 50);
INSERT INTO some_table2 VALUES (1002, 1, 60);
Dublicates occures when two insertions done:
INSERT INTO TEST_TABLE (id,period,amount) SELECT id,period,amount from some_table1
INSERT INTO TEST_TABLE (id,period,amount) SELECT id,period,amount from some_table2
new sqlfiddle link: http://sqlfiddle.com/#!4/cd45b/1
May be it can be solved during insertion from two table..
A script like this would do what you want:
CREATE TABLE test_table_summary (
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO test_table_summary (id, period, amount)
SELECT id, period, SUM(amount) AS total_amount FROM test_table
GROUP BY id, period;
DELETE FROM test_table;
INSERT INTO test_table (id, period, amount)
SELECT id, period, total_amount FROM test_table_summary;
DROP TABLE test_table_summary;
But you should actually decide if test_table is to have a primary key and the total amount or all the detail data. It's not a good solution to use one table for both.
By what you have added, then I'd say you can use the Oracle MERGE INTO statement:
MERGE INTO test_table t
USING (SELECT id, period, amount FROM some_table1) s
ON (t.id=s.id AND t.period=s.period)
WHEN MATCHED THEN UPDATE SET t.amount=t.amount+s.amount
WHEN NOT MATCHED THEN INSERT (t.id, t.period, t.amount)
VALUES (s.id, s.period, s.amount);
Beware though... this will work only if test_table already has no duplicate id, period rows to begin with. So if your table is already messed up, you still have to reinitialize it properly a first time (and maybe add a unique id, period key to avoid problems in the future).

sql question about ordering after a sum

i have a products table that contains all the sales as in quantity made at a time .. so the table is :
id | product_department_id | product_id | quantity_sold
i need to list for all the product_department_ids the best 2 selling products . Any ideas how i can do so ?
if you can do it in pl/sql it would be great but sql is ok also !
Thanks !
drop table quantity;
create table quantity (
id number primary key,
product_department_id number,
product_id number,
quantity_sold number,
unique (product_department_id, product_id)
);
insert into quantity values (1, 1, 1, 10);
insert into quantity values (2, 1, 2, 20);
insert into quantity values (3, 1, 3, 30);
insert into quantity values (4, 2, 1, 60);
insert into quantity values (5, 2, 2, 50);
insert into quantity values (6, 2, 3, 40);
select * from (
select quantity_sold, product_id, product_department_id,
row_number() over (partition by product_department_id order by quantity_sold desc) r
from quantity
) where r < 3;
Edit Still not sure about what exactly was asked, but if the combination prodcut/department can have multple entries then it would be:
drop table quantity;
create table quantity (
id number primary key,
product_department_id number,
product_id number,
quantity_sold number
);
insert into quantity values ( 1, 1, 1, 15);
insert into quantity values ( 2, 1, 1, 15);
insert into quantity values ( 3, 1, 1, 15);
insert into quantity values ( 4, 1, 2, 20);
insert into quantity values ( 5, 1, 3, 30);
insert into quantity values (10, 2, 1, 60);
insert into quantity values (11, 2, 2, 50);
insert into quantity values (12, 2, 3, 40);
insert into quantity values (13, 2, 3, 30);
select * from (
select sum(quantity_sold),
product_id, product_department_id,
row_number() over (partition by product_department_id
order by sum(quantity_sold) desc
) r
from quantity
group by product_department_id, product_id
) where r < 3
order by product_department_id, product_id;
If a product can have only one department, you can simply order by:
select product_department_id
from YourTable
where rownum < 3
order by
quantity_sold desc