oracle sql counts - sql

If portfolio id has the stock code using the count.
example Portfolio id 500 has stock_code 'IBM' It count one Portfolio id 500 has stock_code 'GBA' it counts two
If input Portfolio id 500 and stock_code 'ABC' It count 0
not raising an error message because of the stock_code is exist.
Portfolio id stock_code
500 IBM
500 GBA
500 GBA
select count(distinct stock_code,portfolio_number)
into V_count
from Stock
where P_Stock_Code = stock_code
and P_Portfolio_number=portfolio_number;
showing error
invalid number of arguments
pass two INPUT parameters
or maybe I can not verify the id own or not own the stock_code using count??

As you can already understand you can not pass two parameters to COUNT function. But You can do something like below instead.
WITH STOCK
AS (SELECT 500 PORTFOLIO_ID, 'IBM' AS STOCK_CODE FROM DUAL
UNION ALL
SELECT 500 PORTFOLIO_ID, 'GBA' AS STOCK_CODE FROM DUAL
UNION ALL
SELECT 500 PORTFOLIO_ID, 'GBA' AS STOCK_CODE FROM DUAL)
SELECT CASE WHEN CNT = 0 THEN 'CASE1' WHEN CNT >= 1 THEN 'CASE2' END KEYZ
FROM ( SELECT STOCK_CODE, COUNT (PORTFOLIO_ID) AS CNT
FROM STOCK
GROUP BY STOCK_CODE)

I think you are just trying to check if Passed P_Portfolio_number has how many distinct P_Stock_Code.
You can use the following:
select count(distinct stock_code)
into V_count -- 0,1,2 .. you can use it wherever you want then
from Stock
where P_Stock_Code = stock_code
and P_Portfolio_number=portfolio_number;
Cheers!!

You can use the below
select count(1)
into V_count
from (select distinct stock_code, portfolio_number
from Stock
where P_Stock_Code = stock_code
and P_Portfolio_number = portfolio_number);

Oracle does not support a list of columns in COUNT DISTINCT. I wrote an according request in Oracle's database ideas portal more than two years ago: https://community.oracle.com/ideas/18664. You can register and then upvote this idea. I think, however, that for the given situation you don't need it.
Just use COUNT(*). The following counts the rows for a given combination of stock code and portfolio number (1 for 500|IBM, 2 for 500|GBA, 0 for 500|ABC).
In PL/SQL:
create or replace procedure myproc(p_stock_code varchar2, p_portfolio_number integer) as
v_count integer;
begin
select count(*)
into v_count
from stock
where stock_code = p_stock_code
and portfolio_number = p_portfolio_number;
dbms_output.put_line(v_count);
end myproc;
In SQL:
select count(*)
from stock
where stock_code = :p_stock_code
and portfolio_number = :p_portfolio_number;

Related

PL/SQL SUM Difference Example

I'm trying to implement this SQL code in PL/SQL
SQL Code:
select SUM(SUM(distinct inv_total) - SUM(distinct credit_total) ) as TOTAL from invoice
where cus_id =95
group by inv_total, credit_total
PL/SQL Code:
Declare
total invoice.inv_total%TYPE;
cust_id NUMBER := 95;
BEGIN
select SUM(SUM(distinct inv_total) - SUM(distinct credit_total) )
INTO total from invoice
where cus_id= cust_id;
dbms_output.put_line('Total is ' || total);
END;
ERROR at line 1:
ORA-00978: nested group function without GROUP BY
ORA-06512: at line 8
Any tips how to use GROUP BY with PL/SQL?
Thank you
You seem to have several problems:
I find it highly unlikely that you actually want distinct inv_total or credit_total. If two invoices have the same total, you only want to count one of them?
Without the distinct, the sum can be written 'SUM(inv_total - credit_total)'. This is much more straightforward and will not require a group by clause.
Your original query groups by inv_total and credit_total. This also doesn't seem right, as you're unlikely want to group multiple rows based on totals like this.
If you really wanted the distinct and the group by, then you'd have to include the group by in the PL/SQL block, just as it is in your original SQL statement.
Try this:-
DECLARE
total invoice.inv_total%TYPE;
cust_id NUMBER := 95;
BEGIN
select SUM( inv_total - credit_total)
INTO total from invoice
where cus_id= cust_id;
dbms_output.put_line('Total is ' || total);
END;
/
you can write the code as;
Declare
total invoice.inv_total%TYPE;
cust_id NUMBER := 95;
BEGIN
select SUM(
(select distinct i1.inv_total
from invoice i1
where i1.cus_id = I.cus_id )
)
-
SUM(
(select distinct i2.credit_total
from invoice i2
where i2.cus_id = I.cus_id )
)
INTO total
from invoice i
where i.cus_id= cust_id;
dbms_output.put_line('Total is ' || total);
END;
you can also write the code as
Declare
total invoice.inv_total%TYPE;
cust_id NUMBER := 95;
BEGIN
select SUM(inv_total - credit_total)
INTO total
from (select distinct i1.inv_total, i1.credit_total
from invoice i1
where i.cus_id = cust_id )
);
dbms_output.put_line('Total is ' || total);
END;
choose which suites your requirements
If were me
select cus_id, SUM(SUM(inv_total) - SUM(credit_total) )
INTO cus_id, total
from invoice
where cus_id= cust_id
group by cus_id;

Oracle PL/SQL, I want to retrieve the details of the product which has the price closest to 4.23

create or replace procedure nearprice
is
userprice products.price%type := 4.23;
closest products.price%type;
temp products.price%type;
tempid products.pid%type;
cursor procur is
select * from products;
prorec procur%rowtype;
begin
open procur;
fetch procur into prorec;
closest := abs(prorec.price - userprice);
tempid := prorec.pid;
while procur%found then
loop
fetch procur into prorec;
temp := abs(prorec.price - userprice);
if temp < closest then
closest := temp;
tempid = prorec.pid;
end if;
end loop;
close procur;
select *
from products
where pid = tempid;
end;
I want to retrieve the record in the products table which has the price closest to 4.23.
'products' is a table with pid as primary key and datatype of price is number(*,2);
In this procedure I try to find the minimum of the absolute value of the difference between 4.23 and the price, fetched by the cursor prorec and print all details corresponding to it. I keep getting
Warning: Procedure created with compilation errors
I'm new to PL/SQL so can anyone tell me what mistake I'm doing here? Thanks in advance.
I think the easiest way to do this is with a query:
select p.*
from (select p.*
from products p
order by abs(price - 4.23)
) p
where rownum = 1;
You don't need a cursor to do this calculation.
EDIT:
KZ makes a very good point in the comments about the use of indexes on a large table. The query looks more complicated, but it can use an index:
select p.*
from (select p.*
from ((select p.*
from (select p.*
from products p
where price <= 4.23
order by price desc
) p
where rownum = 1
) union all
(select p.*
from (select p.*
from products p
where price > 4.23
order by price
) p
where rownum = 1
)
) p
order by abs(price - 4.23)
) p
where rownum = 1;
ALthough it looks complicated, the idea is simple. Select one row where the price is less than or equal to the cutoff. Select one row where the price is greater than the value. Then choose the closest value.

SELECT totals from previous SELECT using SQL*Plus

Using SQL*Plus to generate a listing that is e-mailed to a customer, e.g.:
SET MARKUP HTML ON
SPOOL spool.html
SELECT order_number, entry_date, delivery_date, customer_order_number, order_totals_quantity, TRUNC(order_totals_sqm,2), order_totals_net_value FROM orders WHERE entry_date = SYSDATE;
How can I also create a row that shows the total of the listed order_totals fields and keep them in line with those fields?
i.e. if I did a separate SELECT COUNT() for those fields it would list them under the first 3 when really they need to be underneath the original SELECT.
Update: This is what I'm looking for, if it's possible.
other columns ... order_totals_quantity | TRUNC(order_totals_sqm,2) | order_totals_net_value
--------------------------------------------------------------------------------------------
Total | Total | Total
Maybe...
Depends on what aggregate you're wanting and what denotes a unique record so as not to sum quantities incorrectly.
SELECT order_number, entry_date, delivery_date, customer_order_number,
sum(order_totals_quantity), sum(TRUNC(order_totals_sqm,2)), sum(order_totals_net_value)
FROM orders
WHERE entry_date = SYSDATE;
GROUP BY GROUPING SETS ((order_number, entry_date, delivery_date, customer_order_number),
())
Example found: http://www.oracle-base.com/articles/misc/rollup-cube-grouping-functions-and-grouping-sets.php
Try this [assuming you are using oracle]:
SELECT order_number, entry_date, delivery_date, customer_order_number, order_totals_quantity, TRUNC(order_totals_sqm,2), order_totals_net_value,tot.a, tot.b
FROM orders, (select sum(order_totals_quantity) a, sum(order_totals_net_value ) b from orders WHERE entry_date = SYSDATE) tot
WHERE entry_date = SYSDATE;
As you are using SQL*Plus, there is an easier method using computes. This has the advantage of no extra SQL running on the server. Here is an example you can adapt for your query:
BREAK ON report
COMPUTE SUM LABEL total OF a ON report
SELECT 1 AS a FROM dual UNION ALL
SELECT 2 AS a FROM dual UNION ALL
SELECT 3 AS a FROM dual;
A
-------------
1
2
3
-------------
6
3 rows selected.
You can use other aggregates as well. Here is a link to the full documentation: COMPUTE.

select least row per group in SQL

I am trying to select the min price of each condition category. I did some search and wrote the code below. However, it shows null for the selected fields. Any solution?
SELECT Sales.Sale_ID, Sales.Sale_Price, Sales.Condition
FROM Items
LEFT JOIN Sales ON ( Items.Item_ID = Sales.Item_ID
AND Sales.Expires_DateTime > NOW( )
AND Sales.Sale_Price = (
SELECT MIN( s2.Sale_Price )
FROM Sales s2
WHERE Sales.`Condition` = s2.`Condition` ) )
WHERE Items.ISBN =9780077225957
A little more complicated solution, but one that includes your Sale_ID is below.
SELECT TOP 1 Sale_Price, Sale_ID, Condition
FROM Sales
WHERE Sale_Price IN (SELECT MIN(Sale_Price)
FROM Sales
WHERE
Expires_DateTime > NOW()
AND
Item_ID IN
(SELECT Item_ID FROM Items WHERE ISBN = 9780077225957)
GROUP BY Condition )
The 'TOP 1' is there in case more than 1 sale had the same minimum price and you only wanted one returned.
(internal query taken directly from #Michael Ames answer)
If you don't need Sales.Sale_ID, this solution is simpler:
SELECT MIN(Sale_Price), Condition
FROM Sales
WHERE Expires_DateTime > NOW()
AND Item_ID IN
(SELECT Item_ID FROM Items WHERE ISBN = 9780077225957)
GROUP BY Condition
Good luck!

Find Duplicates in SQL and UPDATE them?

I'm trying to find all duplicates in a Table and change one of their values.
Now i use:
SELECT Amount
FROM Bids
GROUP BY Amount, AuctionID
HAVING ( COUNT(Amount) > 1 ) AND (AuctionID=1)
The problem that it returns only
Amount
23.6500
41.8800
42.3500
And not
Amount
23.6500
23.6500
41.8800
41.8800
42.3500
42.3500
So I can't UPDATE all the rows.
How can I get it the way I showed?
Thanks,
Dan
Just wrap it inside an IN query:
SELECT Amount
FROM Bids
WHERE Amount IN (
SELECT Amount
FROM Bids
GROUP BY Amount, AuctionID
HAVING ( COUNT(Amount) > 1 ) AND (AuctionID=1)
)
UPDATE: added UPDATE statement
UPDATE Bids
SET Burned = 1
WHERE Amount IN (
SELECT Amount
FROM Bids
GROUP BY Amount, AuctionID
HAVING ( COUNT(Amount) > 1 ) AND (AuctionID=1)
)
Assume that you have Id in Bids table:
SELECT Amount
FROM Bids b1
WHERE AcutionId = 1
AND EXISTS (Select 1 from Bids b2
WHERE b2.AuctionID = b1.AuctionId
AND b1.Amount = b2.Amount
AND b1.Id <> b2.Id)
I'm curious to know why your original select doesn't satisfy your requirement. If for every member within a set of duplicates you're only selecting one of them, then you have one to update. It should be informative to add AuctionId to the select provided by Frank Schmitt to see what distinguishes these rows.