SubQuery returning Multiple rows - sql

I have got Two Tables
Product (Id, Name, CCode)
Category (CCode, CatName) - No Primary Key
Insert Into ProductNew (DW_Prod_Id, ProdId, ProdName, CC, CName)
Select Dw_Prod_Id.Nextval, Id, Name, CCode,
(Select CatName
From Category cc, Product p
Where cc.CCode IN p.CatCode
Group By CatName )
From Product;
SQL Error: ORA-01427: single-row subquery returns more than one row
01427. 00000 - "single-row subquery returns more than one row"
I am getting the above error Because my SubQuery returns more than one row.
I would like to Match the CatCode of each row from Product table to the Category Table so that I can obtain the CatName and then Insert rows into my New Table :)

if product can have only one category :
INSERT INTO ProdcutNew (DW_Prod_Id, ProdId, ProdName, CC, CName)
(SELECT Dw_Prod_Id.Nextval, p.Id, p.Name, cc.CCode, cc.CName
FROM Product p
INNER JOIN Category cc on p.CatCode = cc.CCode)
And you can correct your table name
ProdcutNew
to ProductNew ;)
EDIT :
But if, as #Gordon Linoff pointed, you have duplicates CCode, this won't work.
If you don't want a primary key on Category table, add at least a unique constraint (you'll have to clean your datas first)
ALTER TABLE Category ADD CONSTRAINT Unique_code UNIQUE(CCode);
EDIT 2 :
But the proper way would be :
Add an Id in Category as PK, and use it as Category_ID FK in Product (if CCode can change)
With the unique constraint on CCode.

You appear to have dulicates in your category table; otherwise a simple join would suffice:
select p.*, c.ccode
from Category c join
Product p
on c.ccode = p.catcode
To choose one category arbitrarily, do something like:
select p.*, c.ccode
from (select c.*
from (select c.*, row_number() over (partition by c.ccode order by c.ccode) as seqnum
from Category c
) c
where seqnum = 1
) c join
Product p
on c.ccode = p.catcode

Related

Finding max count of product

I am trying to find max count of product. The result must only display the brands which have max number of products in it. Can anyone suggest a better way to display result.
Here are the table details:
create table Brand (
Id integer PRIMARY KEY,
Name VARCHAR(40) NOT NULL
)
create table Product (
ID integer PRIMARY KEY,
Name VARCHAR(40) NOT NULL,
Price integer NOT NULL,
BrandId integer NOT NULL,
CONSTRAINT BrandId FOREIGN KEY (BrandId)
REFERENCES Brand(Id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
I have used this SQL query below but I am seeing an error below. The result must display the list of the brands that have max number of products as compared to other brands.
select count(p.id) as count, b.name AS brand_name from product p join brand b on b.Id = p.BrandId
where count(p.id) = (select max(count) from product)
group by b.name
ERROR: aggregate functions are not allowed in WHERE
LINE 2: where count(p.id) = (select max(count) from product)
^
SQL state: 42803
Character: 105
In Postgres 13+, you can use FETCH WITH TIES:
select count(*) as count, b.name AS brand_name
from product p join
brand b
on b.Id = p.BrandId
group by b.name
order by count(*) desc
fetch first 1 row with ties;
In older versions you can use window functions.

Select MAX price of a book with JOIN (2 tables) in SQL Server?

I have 2 tables
CREATE TABLE BOOKS
(
numbk INT PRIMARY KEY IDENTITY,
nombk NVARCHAR(60),
_numrub INT FOREIGN KEY REFERENCES CLASSIFICATION(numrub)
)
CREATE TABLE TARIFER
(
_numbk INT FOREIGN KEY REFERENCES BOOKS(numbk),
_nomed NVARCHAR(60) FOREIGN KEY REFERENCES EDITEURS(nomed),
_date DATE,
price DECIMAL(20,2),
PRIMARY KEY (_numouv, _nomed)
)
The question is: how do I list all titles of books (nombk) that have the max price?
PS: TRAFIER has the price columns, and a foreign key from BOOKS which is _numbk
I tried this:
select
o.nombk, max(prix)
from
TARIFER tr, books o
where
o.numbk = tr._numbk
group by
o.nombk
This lists all, but when I execute this:
select max(prix)
from TARIFER tr, books o
where o.numbk = tr._numbk
It returns only the max price. I don't know why. Could someone please explain?
In SQL Server, you can use TOP (1) WITH TIES:
select top (1) with ties b.nombk, t.prix
from books b join
TARIFER t
on b.numbk = t._numbk
order by t.prix desc;
Why not use just a subquery the get the max(prix) and then use that one to list all records with that prix:
select o.nombk ,prix
from TARIFER tr , books o
where o.numbk = tr._numbk
and tr.prix in (select max(prix) from TARIFER tr)
Both queries to aggregation, but not at the same level:
The first query has group by o.nombk, so it generate one record per book, and gives you the maximum price of this book accross all tarifers.
The second query has no group by clause, hence it gives you the maximum price of all books over all tarifers.
If you want the book with the higher price, there is no need to aggregate: you can join and sort the results by price:
select top (1) with ties b.*, t.*
from books b
inner join join tarifer t on b.numbk = t._numbk
order by t.prix desc;
top (1) with ties gives you the first record; if there are several records with the same, top price, the query returns them all.

calculating sum from another table using SQL

I have a table (District) have columns (Id - District name) . And another table (delivery) have columns (quantity - district Id). can i have a result like a table with every district name in a column and sum of quantity in other column using sql?
I understand that this question will be closed as this site is not about doing homework
select a.district_name, b.total
from District as a
inner join
(
select district_id, sum(quantity) as total
from delivery
group by district_id
) as b
on a.id = b.district_id
Try below code
SELECT dis.district_name,SUM(del.quantity) as quantity
FROM district as dis
INNER JOIN delivery as del
ON dis.id = del.district_id
GROUP BY del.district_id
you can use this code:
SELECT ID, Name, SUM(Quantity) AS SumOfQuantity
FROM
(
SELECT District.ID, District.Name, Delivery.Quantity
FROM District, Delivery
WHERE District.Id = Delivery.DistrictID
) AS T1
GROUP BY ID, Name

How to select members of a special kind of relationship in sql

I have 3 table as follow :
s(s# int,sname nchar(10))
p(p# int,pname nchar(10))
sp(s# int,p# int)
table "s" is table of suppliers and "s#" is primary key of it.also table "p" is table of products and "p#" is primary key on it."s#" and "p#" are foreign key in table "sp".
now my question is "How can I select name of suppliers from table "s" which producing all of products in table "p"...
SELECT p.*, s.sname FROM s, sp, p WHERE s.s# = sp.s# AND sp.p# = p.p#;
This statement will output all products with all their suppliers.
Now we group my suppliers, and count how many products they provide:
SELECT s.sname, count(*) FROM s, sp, p WHERE s.s# = sp.s# AND sp.p# = p.p# GROUP BY s.s#;
Now we know exacly, how many products each supplier provides. And we also know, how many products are in the productstable:
SELECT count(*) FROM p;
If you compare these values, you get your desired result:
SELECT amounts.name FROM
( SELECT s.sname AS name, count(*) AS offers
FROM s, sp, p
WHERE s.s# = sp.s# AND sp.p# = p.p#
GROUP BY s.s# ) amounts, -- this is a temp. tablename
( SELECT count(*) AS avaiable FROM p ) countTbl
WHERE amounts.offers = countTbl.avaiable;
Notice, that I didn't test the query. But you should get an idea on how to solve this problem.
It might also be possible to write this query more efficient, but this one can be understood easily.
There are two ways to do this, the first I thought of was to invert the logic.
Rather than attempting to find every entry of P let's just look for any that don't exist, then exclude those entries from S:
SELECT *
FROM S
WHERE
NOT EXISTS (
SELECT *
FROM P
LEFT JOIN SP
ON P.P# = SP.P#
AND SP.S# = S.S#
WHERE
SP.P# IS NULL
)

take each maximum value of a column and get information from another table

i have two tables:
create table saller(
id_saller int IDENTITY PRIMARY KEY,
name varchar(50),
branch varchar(10)
);
create table sale(
id_sale int IDENTITY PRIMARY KEY,
amount float,
id_saller int,
CONSTRAINT fk_saller FOREIGN KEY (id_saller)REFERENCES saller(id_saller)
);
i wanna get the biggest selling value of the amount for each branch
and get the name and id of the saller in charge for the biggest selling
i tried this:
SELECT saller.name, saller.id_saller,maxv.branch, maxv.maxbranch
FROM saller
INNER JOIN sale
ON saller.id_saller = sale.id_saller
INNER JOIN (
SELECT saller.branch,saller.id_saller,MAX(sale.amount) AS maxbranch
FROM saller
INNER JOIN sale
ON saller.id_saller = sale.id_saller
GROUP BY saller.branch,saller.id_saller
) AS maxv ON(sale.id_saller = maxv.id_saller)
One way to do it if you want to return exactly one row per branch even if you have ties
SELECT branch, id_saller, name, amount
FROM
(
SELECT r.branch, s.id_saller, r.name, s.amount,
ROW_NUMBER() OVER (PARTITION BY r.branch ORDER BY s.amount DESC) rnum
FROM sale s JOIN saller r
ON s.id_saller = r.id_saller
) q
WHERE q.rnum = 1
or if you want the highest value with ties
SELECT branch, id_saller, name, amount
FROM
(
SELECT r.branch, s.id_saller, r.name, s.amount,
RANK() OVER (PARTITION BY r.branch ORDER BY s.amount DESC) rank
FROM sale s JOIN saller r
ON s.id_saller = r.id_saller
) q
WHERE q.rank = 1
Here is SQLFiddle demo
According to your question, I don't understand the presence of branch, maybe a table that has not been mentionned. But to retrieve the seller id and name, you can try this;
SELECT saller.name, saller.id_saller
FROM saller
INNER JOIN sale
ON saller.id_saller = sale.id_saller
WHERE sale.Amount = (Select Max(Amount) from sale)