The following code executes without error and produces the expected.
SELECT s.product_ID, s.price, s.quantity, d.wholesale_ID
FROM
(
SELECT product_ID, MIN(min_price) as price, quantity
FROM
(
SELECT SUM(ci.quantity) as quantity, MIN(d.price) as min_price, ci.product_ID as product_ID, wholesale_ID
FROM "Customer order" co,
"CO Item" ci,
deal d
WHERE co.processed = 0
AND co.ID = ci.order_ID
AND d.product_ID = ci.product_ID
GROUP BY ci.product_ID, d.wholesale_ID
ORDER BY ci.product_ID
)
GROUP BY product_ID, quantity
ORDER BY product_ID
) s,
deal d
WHERE s.product_ID = d.product_ID
AND s.price = d.price
ORDER BY d.wholesale_ID
When I try to compile it into a procedure as a cursor, I get 'ORA-00907 missing right parenthesis' error. I'm using Oracle SQL Developer.
CREATE OR REPLACE PROCEDURE createWholesaleOrders IS
CURSOR Curser IS(
SELECT s.product_ID, s.price, s.quantity, d.wholesale_ID
FROM
(
SELECT product_ID, MIN(min_price) as price, quantity
FROM
(
SELECT SUM(ci.quantity) as quantity, MIN(d.price) as min_price, ci.product_ID as product_ID, wholesale_ID
FROM "Customer order" co,
"CO Item" ci,
deal d
WHERE co.processed = 0
AND co.ID = ci.order_ID
AND d.product_ID = ci.product_ID
GROUP BY ci.product_ID, d.wholesale_ID
ORDER BY ci.product_ID
)
GROUP BY product_ID, quantity
ORDER BY product_ID
) s,
deal d
WHERE s.product_ID = d.product_ID
AND s.price = d.price
ORDER BY d.wholesale_ID -- < MISSING RIGHT PARENTHESIS HERE
);
Pointer Curser%rowtype;
current_wholesale NUMBER := -1;
current_order NUMBER := -1;
BEGIN
OPEN Curser;
LOOP
FETCH Curser INTO Pointer;
EXIT WHEN Curser%NOTFOUND;
IF current_wholesale != Pointer.wholesale_ID THEN
current_order := wholesale_order_sq.NEXTVAL;
INSERT INTO "Wholesale order" (ID, wholesale_ID, "date") VALUES(current_order, Pointer.wholesale_ID, sysdate);
current_wholesale := Pointer.wholesale_ID;
END IF;
INSERT INTO "WO Item" (ID, order_ID, product_ID, quantity, price)
VALUES(wo_item_sq.NEXTVAL, current_order, Pointer.product_ID, Pointer.quantity, Pointer.price);
UPDATE "CO Item"
SET "CO Item"."wholesale-order_ID" = current_order
WHERE "CO Item".order_ID IN (
SELECT "Customer order".ID
FROM "Customer order"
WHERE "Customer order".processed = 0
)
AND "CO Item".product_ID = Pointer.product_ID;
END LOOP;
UPDATE "Customer order"
SET processed = 1
WHERE processed = 0;
END;
Updated to include full code. There should be no errors on other places.
For whatever reason, the compiler does not accept the parens around the select in this cursor (as originally suggested by a_horse_with_no_name), although there is nothing inherently wrong with it as the following code compiles fine for me:
create or replace
procedure test is
cursor c is (select 1 from dual);
begin
null;
end;
However, if I remove the parens in your code, it does compile and refuses to compile for me otherwise. Sounds like a compiler bug to me.
Related
I have started a simple auction system where each row contains the following data:
Type:= BID|WIT
ProductName := Str
User := Str
Value := Decimal
CreatedAt := datetime
*Here WIT means withdraw, aka quit from item auction *
A user can naturally do multiple bid requests, always raising the bid value (this is handled at language level)
I would like to list all top bids from all users but under a condition, only if they are not before a WITHDRAW request for the given item.
For example, given the entries
BID,Doll,John,10,2021-11-26 10:10
BID,Ball,John,12,2021-11-26 10:11
BID,Doll,Mary,12,2021-11-26 10:12
BID,Doll,Alice,13,2021-11-26 10:13
BID,Doll,Mary,14,2021-11-26 10:14
BID,Doll,Alice,17,2021-11-26 10:14
BID,Ball,Mary,14,2021-11-26 10:14
WIT,Doll,John,00,2021-11-26 10:16
BID,Doll,Mary,20,2021-11-26 10:18
BID,Ball,John,15,2021-11-26 10:20
If I magic_sql_query(Doll) I would like to get
BID,Doll,Alice,17,2021-11-26 10:14
BID,Doll,Mary,20,2021-11-26 10:18
Also If I magic_sql_query(Ball) I would like to get:
BID,Ball,Mary,14,2021-11-26 10:14
BID,Ball,John,15,2021-11-26 10:20
How can I do it in a SQL Statement?
You can
use the row_number() windowing function to rank within a group (a
group is defined by the username and the product); the latest entry
gets rank 1
get rid of all entries whose rank is > 1 (i.e. the user has a later entry for this product)
get rid of all entries of type 'WIT'
with base as (select
b.type,
b.productname,
b.username,
b.value,
b.createdat,
row_number() over (partition by productname, username
order by createdat desc) as rn
from bids b
order by productname, username, createdat
)
select * from base
where rn = 1
and type = 'BID';
SQL Fiddle
To find all bids that have no withdrawal later (by the same user for the same product) you can use a NOT EXITS condition:
select a1.*
where a1.product_name = 'Ball'
and type = 'BID'
and not exists (select *
from auction a2
where a2.product_name = a1.product_name
and a2.user_name = a1.user_name
and a2.type = 'WIT'
and a2.created_at > a1.created_at)
Now we need to filter out the highest bids per product and user. This can be done using the dense_rank() function.
select type, product_name, user_name, value, created_at
from (
select a1.*, dense_rank() over (partition by product_name, user_name order by value desc) as rnk
from auction a1
where a1.product_name = 'Ball'
and type = 'BID'
and not exists (select *
from auction a2
where a2.product_name = a1.product_name
and a2.user_name = a1.user_name
and a2.type = 'WIT'
and a2.created_at > a1.created_at)
) t
where rnk = 1
order by created_at;
Online example
A left join version
select t.Type, product_name, t.User, Value, CreatedAt
from (
select b.*
, row_number() over(partition by b.product_name, b.user order by b.createdAt desc) rn
from auction b
left join auction w
on w.type = 'WIT'
and b.product_name = w.product_name
and b.user = w.user
and w.createdAt > b.createdAt
where b.type = 'BID'
and w.product_name is null
-- and b.product_name = 'Ball'
) t
where rn=1
-- and product_name = 'Ball'
order by product_name, CreatedAt;
uncomment one of .. product_name = 'Ball' to get only this product.
db<>fidlle
You can use MAX() window function to get for each user the last entry with type = 'BID' and the last entry with type = 'WIT'.
Then filter the results:
SELECT type, productname, "user", value, createdat
FROM (
SELECT *,
MAX(CASE WHEN type = 'BID' THEN createdat END) OVER (PARTITION BY "user") last_bid,
MAX(CASE WHEN type = 'WIT' THEN createdat END) OVER (PARTITION BY "user") last_wit
FROM tablename
WHERE productname = ?
) t
WHERE (last_wit IS NULL OR last_wit < last_bid) AND createdat = last_bid;
Replace ? with the name of the product that you want.
See the demo.
I need your help again. Here's my SQL query :
SELECT sp.pro_ID, description, price, sp.sup_ID
FROM L4_Sup_Pro sp, L4_Products prod
WHERE prod.our_id = sp.pro_id
AND (sp.sup_ID = '23' OR sp.sup_ID = '75')
ORDER BY sp.pro_ID;
And this query gives me this result :
I need to compare the prices of SUP_ID column having values 75 and 23, and display the cheapest price. So output will be:
PRO_ID DESCRIPTION PRICE SUP_ID
101 Laser Printer 630 23
121 Color Jet Printer 223 23
302 Scanner 399 75
You can use ROW_NUMBER() analytic function
SELECT pro_ID, description, price, sup_ID
FROM
(
SELECT sp.pro_ID, description, price, sp.sup_ID,
ROW_NUMBER() OVER (PARTITION BY description ORDER BY price ) as rn
FROM L4_Sup_Pro sp
JOIN L4_Products prod
ON prod.our_id = sp.pro_id
WHERE sp.sup_ID in (23,75) -- without quotes by considering SUP_ID is a numeric column
)
WHERE rn = 1
ORDER BY pro_ID
Demo
Presuming columns description, and price stored on L4_Products, you can try below query -
SELECT sp.pro_ID, prod.description, prod.price, sp.sup_ID
FROM L4_Sup_Pro sp
JOIN (SELECT our_id, description, MIN(price) price
FROM L4_Product
GROUP BY our_id, description) prod ON prod.our_id = sp.pro_id
WHERE sp.sup_ID = '23'
OR sp.sup_ID = '75'
ORDER BY sp.pro_ID;
One method is aggregation:
SELECT sp.pro_ID, description,
MIN(price),
MIN(sp.sup_ID) KEEP (DENSE_RANK FIRST ORDER BY price) as min_sup_ID
FROM L4_Sup_Pro sp JOIN
L4_Products prod
ON prod.our_id = sp.pro_id AND
WHERE sp.sup_ID IN (23, 75) -- looks like a number so I dropped the quotes
GROUP BY p.pro_ID, description
You just need a group by with having
SELECT sp.pro_ID, description,
min(price) , min(sp.sup_ID)
FROM L4_Sup_Pro sp, L4_Products
prod
WHERE prod.our_id = sp.pro_id AND
(sp.sup_ID = '23' OR sp.sup_ID = '75')
Group by s.pro_id,description having
1=
Max(case when price=min(price)
then 1
else 0 end)
ORDER BY sp.pro_ID;
I have one table there have so many item code, then i select '09015','09002','09025','09026' these item code, where pat_no = '33516', the problem is how can i compare the max rpt_time from these item code??
Here is my T-SQL query:
SELECT
[pat_no],[item_code],[value],[rpt_time]
FROM
[Tmhtc_PHR].[dbo].[lab_item]
WHERE
[pat_no] = '33561'
AND ([item_code] = '09015' OR [item_code] = '09002' OR [item_code] = '09025' OR [item_code] = '09026')
ORDER BY
[rpt_time] DESC
Result:
You could use one of two queries below:
SELECT
pat_no, item_code, [value], rpt_time
FROM Tmhtc_PHR.dbo.lab_item
WHERE pat_no, item_code, rpt_time IN (
SELECT pat_no, item_code, MAX(rpt_time)
FROM Tmhtc_PHR.dbo.lab_item
WHERE pat_no = '33561'
AND item_code IN ('09015', '09002', '09025', '09026')
GROUP BY item_code
)
ORDER BY pat_no, item_code;
Or
SELECT
i.pat_no, i.item_code, i.[value], i.rpt_time
FROM Tmhtc_PHR.dbo.lab_item i
INNER JOIN (
SELECT pat_no, item_code, MAX(rpt_time) AS max_rpt_time
FROM Tmhtc_PHR.dbo.lab_item
WHERE pat_no = '33561'
AND item_code IN ('09015', '09002', '09025', '09026')
GROUP BY item_code
) im
ON i.pat_no = im.i.pat_no AND i.item_code = im.item_code AND i.rpt_time = im.max_rpt_time
ORDER BY i.pat_no, i.item_code;
Pretty straight forward. What is wrong with this statement.
SELECT DISTINCT CUST_FNAME "FIRST NAME", CUST_LNAME "LAST NAME", POS_TIME "TIME", POS_DATE "DATE" FROM POS, CUSTOMER
WHERE CUST_NUM = POS_CUST_NUM AND POS_ITEMID = 1 AND POS_ITEMID = 2;
I think you might want customers who are associated with BOTH items 1 and 2. In that case you can use the following:
select x.*, pos_time, pos_date
from (SELECT CUST_NUM, CUST_FNAME, CUST_LNAME
FROM POS
join CUSTOMER
on CUST_NUM = POS_CUST_NUM
where POS_ITEMID = 1
intersect
SELECT CUST_NUM, CUST_FNAME, CUST_LNAME
FROM POS
join CUSTOMER
on CUST_NUM = POS_CUST_NUM
where POS_ITEMID = 2) x
join pos
on x.cust_num = pos.pos_cust_num
where pos_itemid in (1, 2)
Not sure, but this might be a little more efficient than the intersect that Brian did above. Also, I don't have access to a database right now, so my syntax may be slightly off.
select CUST_NUM, CUST_FNAME, CUST_LNAME, pos_time, pos_date
from CUSTOMER c1,POS p1
where c1.cust_num = p1.pos_cust_num
and p1.pos_itemid=1
and exists (select 'x' from
pos p2
where p2.pos_cust_num=p1.pos_cust_num
and p2.pos_itemid=2)
basically, give me everyone where the ordered itemid 1 and where a record exists where the same customer ordered itemid 2.
Each item in c_data is in a category/section. I would like to limit how many items are displayed per category, rather than limiting the total number of items retrieved. Obviously if I add something like "limit 20" to the query, it will only fetch 20 results in total, rather than 20 results per category.
SELECT cm.id,
cm.title AS cmtitle,
cm.sectionid,
cm.type AS cmtype,
cd.id,
cd.time,
cd.link,
cd.title,
cd.description,
cd.sectionid AS sectionid
FROM c_main AS cm
JOIN c_data AS cd ON cd.sectionid=cm.sectionid
WHERE cd.sectionid=cm.sectionid
ORDER by id ASC
The field with the category is "sectionid".
MySQL doesn't have any ranking functionality, but you can use a variable to create a psuedo row number.
Use:
SELECT x.*
FROM (SELECT cm.id,
cm.title AS cmtitle,
cm.sectionid,
cm.type AS cmtype,
cd.id AS cd_id,
cd.time,
cd.link,
cd.title,
cd.description,
cd.sectionid AS cd_sectionid,
CASE
WHEN #sectionid != cm.sectionid THEN #rownum := 1
ELSE #rownum := #rownum + 1
END AS rank,
#sectionid := cm.sectionid
FROM C_MAIN cm,
C_DATA cd,
(SELECT #rownum := 0, #sectionid := NULL) r
WHERE cm.sectionid = cd.sectionid
ORDER BY cm.sectionid) x
WHERE x.rank <= 20
ORDER BY id
The answers to this previous post should help you to solve that problem.
EDIT:
It should work with using row numbers.
I have not tried it, but this should work:
set #section = '';
set #num = 1;
SELECT y.*
FROM
(
SELECT
x.*,
#num := if(#section = sectionid, #num + 1, 1) as row_number,
#section := sectionid
FROM
(
SELECT
cm.id AS cm_id,
cm.title AS cmtitle,
cm.sectionid,
cm.type AS cmtype,
cd.id AS cd_id,
cd.time,
cd.link,
cd.title,
cd.description
FROM c_main AS cm
JOIN c_data AS cd ON ( cd.sectionid=cm.sectionid )
ORDER by cd.sectionid ASC, cm.id ASC
) x
) y
WHERE y.row_number <= 20;