How to select max price using multiple query - sql

i have create tow table, table and data inserting value are given below :
create table product (
pid number(10) primary key,
pname varchar2(30)
);
INSERT INTO product values(100,'Apple');
INSERT INTO product values(101,'Banana');
INSERT INTO product values(102,'Pinaple');
INSERT INTO product values(103,'Orange');
create table purchase(
invid number(10) primary key,
pid number(10),
pprice number(10)
);
alter table purchase add(constraint pid_fk FOREIGN KEY (pid) references product(pid));
INSERT INTO purchase values(10,101,30);
INSERT INTO purchase values(11,103,35);
INSERT INTO purchase values(12,103,9);
INSERT INTO purchase values(13,103,22);
INSERT INTO purchase values(14,101,12);
now i have select table purchase show give data
invid pid pprice
10 101 30
11 103 35
12 103 9
13 103 22
14 101 12
now i want to be last insert price pid=103
now need show pprice=22
i have all ready done the task using two query such as:
select max(invid) from purchase where pid=103;
result is 22 and running next statement
select max(pprice) from purchase where invid=13;
show result =22
i want to show result 22 using running one statment,

Probably the most direct way is to use a subquery:
SELECT MAX(pprice)
FROM purchase
WHERE invid = (SELECT MAX(invid) FROM purchase WHERE pid = 103)
Side note, you don't need to MAX() pprice based on your sample data, but I left it that way in case you need it for your real data set.

The aggregate FIRST/LAST function is made exactly for this kind of task. Unfortunately it seems the vast majority of developers don't use it - either because they are not aware of its existence, or because they don't understand how it works, or for who knows what other reason.
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions056.htm
The function allows for the case when the max(invid) (in your model) is not unique; in which case you must decide WHICH pprice to select. You can select the max, or min, or average pprice (or the sum for that matter), from all those that have pid = 103 and the max value in the invid column. Of course, if the max(invid) is unique (as it is in your problem), then all these functions will return just the pprice associated to that invid; but you must still use one of these aggregate functions, since that uniqueness is not known at parsing time, it is only known at execution time. min is conventionally used in this manner. So:
select min(pprice) keep (dense_rank last order by invid) as pprice
from ........
where pid = 103
;

Related

Design a table in a RDB to sales of multiple items, and calculate the value of the sale

I'm designing a DB for a Mock app and I'm having issues conceptualizing the design of the "Sales" Table.
Supposing I have a
CASHIER table with ID as its PK, name and lname
ARTICLE table with ARTICLE_ID as PK, description, price, stock
SALES table with SALE_ID(pk), ARTICLE_ID(FK article), CASHIER_ID(fk for cashier ID), TOTAL_PRICE_OF_SALE , PRICE_OF_UNIT(FK to ARTICLE price) and UNITS_SOLD
how can I design SALES in such a way that several articles can be sold in 1 transaction?
Normalization rules speak against having a column hold several values, so I don't see how I could store all of the article_id that were sold in a transaction inside an array. Calculating the price also seems problematic.
I know that in DML, you can display a PK several times, but as far as I know, in DDL you can't insert a row with a repeated PK, so I don't see how I could achieve something like
SALE_ID | ARTICLE_ID | CASHIER_ID | TOTAL_PRICE_OF_SALE | PRICE_OF_UNIT | UNITS_SOLD
1 1ASB JOHNDOE1 50.00 25.00 1
1 351A JOHNDOE1 50.00 10.00 1
1 JS57 JOHNDOE1 50.00 15.00 1
In DDL.
Notice that TOTAL_PRICE_OF_SALE should also calculate its value on it's own, during insertion time, but I also don't know how to handle the multiplication of price_of_unit * units_sold and then sum all of it into total_price_of_sale.
You need a SALE_ITEM table to link an ARTICLE to a SALE.
CREATE TABLE SALE_ITEM (
SALE_ITEM_ID INT NOT NULL IDENTITY(1,1),
SALE_ID INT NOT NULL REFERENCES SALE(SALE_ID),
ARTICLE_ID INT NOT NULL REFERENCES ARTICLE(ARTICLE_ID),
QUANTITY INT,
-- Its usually safer to copy the price into the 'item' table
-- so that your order history is accurate even when
-- the price of the article increases
PRICE DECIMAL(9,2)
)
And remove ARTICLE_ID from SALE. Or you might prefer to call it SALE_ARTICLE
BTW when naming tables I recommend choosing to either use plural or singular table names... but don't use a mix as that will be confusing. Hence I have used SALE in this example.
Further I wouldn't use all capitals in table names, instead I would use Pascal Case e.g. SaleItem
Also don't store the total sale price unless you have a concrete requirement to do so. Its much simpler to query that when you need it - otherwise you typically need to add a trigger on SALE_ITEM. An example of the query method:
SELECT SUM(SI.Price*SI.Quantity) TotalPrice
FROM SALE S
INNER JOIN SALE_ITEM SI on SI.SALE_ID = S.SALE_ID;
Note: SALE_ITEM doesn't technically need a SALE_ITEM_ID column as you could use a composite key of SALE_ID,ARTICLE_ID but I prefer to always have a table specific PK.

exclude return values from select clause

i have the below table called reserves in mysql server 8.0:
RESERVES (
res_id INT NOT NULL AUTO INCREMENT,
product_id INT NOT NULL,
start_date DATE NOT NULL,
finish_date DATE NOT NULL,
PRIMARY KEY(res_id),
FOREIGN KEY(product_id) REFERENCES PRODUCT(product_id) ON UPDATE CASCADE ON DELETE RESTRICT
);
the customer will fill a form to specify the dates he want it (start_res_date and finish_res_date), so i have to make a query to check if it is available on this time period.
i am stuck here, mainly because there can be multiple reservations for this specific product.
so, something like this:
SELECT DISTINCT product_id FROM RESERVES
WHERE start_res_date >= finish_date OR finish_res_date <= start_date
won't work, because it will return the product_id if it is ok with the dates of one of its reservetions.
what i want, is to reject its product_id, if it is anavailable for, at least, one reservetion in the table.
any ideas for how to approach it? thanks.
A product is reserved during the time window if any part of its reservation window overlaps with your window. This is easiest to see in graphical form:
i.e. the green bars represent those other reservations which conflict with your booking window / the red bars are bookings which are fully outside your window, so no conflicts occur.
Related to this graphic is a blog post going into a lot more detail:.
You should use SQL such as below to check if a product is available in a given time slot:
select top 1 1 ProductIsNotAvailable
from Reserves
where product_id = #productToBeReserved
and start_res_date < #newReservationFinishDate
and finish_res_date => #newReservationStartDate
i.e. only allow the booking if you don't get the response 1 to the above query.

Row returned by a query with ROWNUM and PRIMARY KEY column

I'm reading about 1 of the oracle pseudocolumns i.e
ROWNUM: which return number indicating the order in which oracle return the row.
I have encountered some behavior here,
Example used
1. Create Script:
CREATE TABLE CUSTOMERS(
ID INT NOT NULL,
NAME VARCHAR (20) NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR (25) ,
SALARY DECIMAL (18, 2),
PRIMARY KEY (ID)
);
2 Insert Script:
INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (2, 'Max', 22, 'India', 4500.00 );
INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY)
VALUES (1, 'Maths', 22, 'US', 4500.00 );
select * from CUSTOMERS; executed in the same order as inserted above,
ID NAME AGE ADDRESS SALARY
------ ---- --- ------- ------
2 Max 22 India 4500.00
1 Math 22 US 4500.00
Here if I run the select query,
select
rownum,
customers.ID
from customers;
I get below output:
ROWNUW ID
------ --
1 1
2 2
Here ID = 2 is inserted first but oracle returns in the 2nd row,
But if you include any other column from a table with ROWNUM and PK like
select
rownum,
customers.ID,customers.Name
from customers;
I get correct output (Correct inserted order) :
ROWNUW ID NAME
------ -- ----
1 2 Max
2 1 Math
If run query without Name column i.e only ROWNUW (pseudocolumns) and PK (table column)
We get this,
ROWNUW ID
------ --
1 1
2 2
My Question is Why is that ID=2 is not first returned row.
if I query any table column with ROWNUM, I get the result back based on insertion order.
Example below
select
rownum,
(NAME / AGE / ADDRESS SALARY) any one of these columns
From CUSTOMERS
But if use ROWNUM with ID (Primary Key column) insertion order is not working. why is this behavior with the only Primary Key column?
ROWNUM values depends on how oracle access the resultset. Once resultset is fetched, rownum is assigned to the rows.
As there is no guarantee in what order the data is returned, there is no guarantee in what order rownum is assigned.
Maybe if you try running both of your queries without rownum, you might get the rows swapped as you showed, or they might not.
Rownum will always be in order of 1,2,3,4 .. no matter what you are getting in result set. It is always calculated after result set is returned from query.
Now, you have ID column as PRIMARY KEY which makes it eligible for default clustered index creation in database. So when you select only PRIMARY column, it will be sorted as it was stored in DB that way. Index created as a result of PRIMARY key creation is sorted in ASC which is default.
Here if you select only PRIMARY KEY column i.e. "ID", Database is returning it in sorted order and ROWNUM is writing 1 & 2 to it.
But if you are selecting some extra non-PRIMARY KEY as well then it is totally upto oracle, whichever way it finds data faster. Sometimes it will return data from cache memory. If not it will read disk and fetch data. While reading datafile, there are multiple things which will differ machine to machine i.e is your table partitioned? is your table sharing tablespace ? what organization you are using in table ? blah blah....
Bottom line is, don't trust ROWNUM. It gives 1,2,3.. after you have applied your brain to the query.

Unique constraint on Distinct select in Oracle database

I have a data processor that would create a table from a select query.
<_config:table definition="CREATE TABLE TEMP_TABLE (PRODUCT_ID NUMBER NOT NULL, STORE NUMBER NOT NULL, USD NUMBER(20, 5),
CAD NUMBER(20, 5), Description varchar(5), ITEM_ID VARCHAR(256), PRIMARY KEY (ITEM_ID))" name="TEMP_TABLE"/>
and the select query is
<_config:query sql="SELECT DISTINCT ce.PRODUCT_ID, ce.STORE, op.USD ,op.CAD, o.Description, ce.ITEM_ID
FROM PRICE op, PRODUCT ce, STORE ex, OFFER o, SALE t
where op.ITEM_ID = ce.ITEM_ID and ce.STORE = ex.STORE
and ce.PRODUCT_ID = o.PRODUCT_ID and o.SALE_ID IN (2345,1234,3456) and t.MEMBER = ce.MEMBER"/>
When I run that processor, I get an unique constraint error, though I have a distinct in my select statement.
I tried with CREATE TABLE AS (SELECT .....) its creating fine.
Is it possible to get that error? I'm doing a batch execute so not able to find the individual record.
The select distinct applies to the entire row, not to each column individually. So, two rows could have the same value of item_id but be different in the other columns.
The ultimate fix might be to have a group by item_id in the query, instead of select distinct. That would require other changes to the logic. Another possibility would be to use row_number() in a subquery and select the first row.

Distribute budget over for ranked components in SQL

Assume I have a budget of $10 (any integer) and I want to distribute it over records which have rank field with varying needs. Example:
rank Req. Fulfilled?
1 $3 Y
2 $4 Y
3 $2 Y
4 $3 N
Those ranks from 1 to 3 should be fulfilled because they are within budget. whereas, the one ranked 4 should not.
I want an SQL query to solve that.
Below is my initial script:
CREATE TABLE budget (
id VARCHAR (32),
budget INTEGER,
PRIMARY KEY (id));
CREATE TABLE component (
id VARCHAR (32),
rank INTEGER,
req INTEGER,
satisfied BOOLEAN,
PRIMARY KEY (id));
INSERT INTO budget (id,budget) VALUES ('1',10);
INSERT INTO component (id,rank,req) VALUES ('1',1,3);
INSERT INTO component (id,rank,req) VALUES ('2',2,4);
INSERT INTO component (id,rank,req) VALUES ('3',3,2);
INSERT INTO component (id,rank,req) VALUES ('4',4,3);
Thanks in advance for your help.
Lee
Well, the example you gave is fairly easy:
select rank, req,
sum(req) over(order by rank) < (select budget from budget where id = '1')
as fulfilled
from component
But this doesn't take into account:
there are 2 units left over from the budget that could be allocated to a further component with a lower requirement
budget is allocated to components rank-first, not sure that's what you meant
So if there was a component (id=5, rank=5, req=2) and that should be fulfilled, this isn't sufficient.
TBH I suspect a function to do the allocation is the best bet- should be quite easy to simply run through the result of a query ordered by "rank asc" and update the fulfilled column according to the current state.