How to display column names from multiple table using sub query - mysql

I have created the following tables and have inserted these values:
create table customer (cid int, cname varchar(25), email varchar(25), phone int, status varchar(25), primary key (cid));
create table accounts( cid int, account int, atype varchar(25), balance int, foreign key(cid) references customer(cid));
create table address( cid int, street varchar(25), city varchar(25), country varchar(25), foreign key(cid) references customer(cid));
insert into customer values (101,'A', 'a#gmail.com', 99,'active');
insert into accounts values (101, 123, 'SA', 1000);
insert into address values (101, 'HMT','Blore','India');
insert into customer values (102,'B', 'b#gmail.com', 199,'active');
insert into accounts values (102, 123, 'CA', 2000);
insert into address values (102, 'Jayanagar','Blore','India');
My objective is to display cname, account and balance of the customers whose status is active.
I have tried writing the query using this: (I am unable to print the column cname using this) But it displays the rest.
select account, balance
from accounts
where cid in (select cid from customer where status = 'active');
this does not work:
select cname, account, balance
from customer, accounts
where cid in (select cid from customer where status = 'active');

One possible way is to join the two tables on the common customer ID.
SELECT c.cname,
a.account,
a.balance
FROM customer c
LEFT JOIN accounts a
ON a.cid = c.cid
WHERE c.status = 'active';

One possible way that worked for me:
SELECT cust.cname,
acc.account,
acc.balance
FROM customer cust,
accounts acc
WHERE cust.cid=acc.cid
AND acc.cid IN
(select cid FROM customer WHERE status='active');

SELECT customer.cname,accounts.account,accounts.balance FROM customer INNER JOIN accounts ON accounts.cid = customer.cid WHERE customer.status = 'active';

Related

Write a SQL query to find and display a customer who made 2 consecutive orders in same category?

Question: Write a SQL query to find and display a customer who made 2 consecutive orders in the same category?
I am struggling with the answer. Any help would be appreciated.
Queries:
CREATE TABLE customers (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name TEXT,
email TEXT);
CREATE TABLE orders (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
customer_id INTEGER,
item TEXT,
price REAL,
ORDER_DATE DATETIME,
category TEXT);
INSERT INTO customers (name, email) VALUES ("Doctor Who", "doctorwho#timelords.com");
INSERT INTO customers (name, email) VALUES ("Harry Potter", "harry#potter.com");
INSERT INTO customers (name, email) VALUES ("Captain Awesome", "captain#awesome.com");
INSERT INTO orders (customer_id, item, price,ORDER_DATE,category)
VALUES (1, "Sonic Screwdriver", 1000.00,'21-04-15 09.00.00','tools');
INSERT INTO orders (customer_id, item, price,ORDER_DATE,category)
VALUES (1, "Light", 1000.00,'21-10-15 09.00.00','tools');
INSERT INTO orders (customer_id, item, price,ORDER_DATE,category)
VALUES (2, "High Quality Broomstick", 40.00,'20-12-20 09.00.00','cleaner');
INSERT INTO orders (customer_id, item, price,ORDER_DATE,category)
VALUES (3, "TARDIS", 1000000.00,'21-01-20 09.00.00','other');
Step: 1
First of all, you add a foreign key in the column containing the customer id of the order table, then after that add the customers and orders tables together.
Step: 2
After adding both tables together run this query and you will get your result.
SELECT DISTINCT orders.category , customers.id,customers.name,customers.email FROM customers JOIN orders ON customers.id= orders.customer_id WHERE orders.category in ( select category from orders group by category having count(*) >= 2 )
You can also solve it by using LEAD. Get lead_category and lead_customers_id and filter with category, customers_id
select * from
(SELECT orders.category , orders.item, customers.id,customers.name,customers.email,
LEAD(category) OVER (ORDER BY customers.id ASC) AS lead_category,
LEAD(customers.id) OVER (ORDER BY customers.id ASC) AS lead_customers_id
FROM orders
JOIN
customers ON
orders.customer_id = customers.id) AS T
where category = lead_category and id = lead_customers_id
SELECT DISTINCT t1.customer_id
FROM orders t1
JOIN orders t2 USING (customer_id, category)
WHERE t1.ORDER_DATE < t2.ORDER_DATE
AND NOT EXISTS ( SELECT NULL
FROM orders t3
WHERE t1.customer_id = t3.customer_id
AND t1.category != t3.category
AND t1.ORDER_DATE < t3.ORDER_DATE
AND t3.ORDER_DATE < t2.ORDER_DATE )
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=a26be6164e027b1a4b0aa9a736764da3
I.e. we simply search for a pair of orders for the same customer and category where an order with the same customer but another category not exists between these orders.
Join customers table if needed.

Error code 1111: says invalid use of group function

Im trying to use
select Suppliers.sid
from Suppliers
left join Catalog on Suppliers.sid=Catalog.sid
where Catalog.cost>avg(Catalog.cost);
but im getting error code 1111:
Unsure what's going on with my database. Im very nice to sql and just having issues getting this to work.
CREATE DATABASE CSC123Lab2;
USE CSC123Lab2;
CREATE TABLE Suppliers (
sid CHAR(20),
sname CHAR(20),
address CHAR(20),
pid CHAR(20)
);
CREATE TABLE Parts (
pid CHAR(20),
pname CHAR(20),
color CHAR(20),
sid CHAR(20)
);
CREATE TABLE Catalog (
sid CHAR(20),
pid CHAR(20),
cost REAL
);
ALTER TABLE Suppliers ADD PRIMARY KEY (sid);
ALTER TABLE Parts ADD PRIMARY KEY (pid);
INSERT INTO Suppliers (sid, sname, address) VALUES (1, "carvel", "1234 Main Street");
INSERT INTO Suppliers (sid, sname, address) VALUES (2, "coldstone", "5678 Pine Street");
INSERT INTO Suppliers (sid, sname, address) VALUES (3, "ralphs", "9876 Oak Street");
INSERT INTO Suppliers (sid, sname, address) VALUES (4, "Acme Widget", "4321 Maple Street");
INSERT INTO Parts (pid, pname, color) VALUES (1, "hammer", "red");
INSERT INTO Parts (pid, pname, color) VALUES (2, "screwdriver", "pink");
INSERT INTO Parts (pid, pname, color) VALUES (3, "nails", "green");
INSERT INTO Parts (pid, pname, color) VALUES (4, "screws", "teal");
INSERT INTO Catalog (sid, pid, cost) VALUES (1, 3, 32);
INSERT INTO Catalog (sid, pid, cost) VALUES (4, 1, 10);
INSERT INTO Catalog (sid, pid, cost) VALUES (4, 3, 48);
INSERT INTO Catalog (sid, pid, cost) VALUES (2, 4, 24);
select Suppliers.sid
from Suppliers
left join Catalog on Suppliers.sid=Catalog.sid
where Catalog.cost>avg(Catalog.cost);
DROP TABLE Catalog;
DROP TABLE Parts;
DROP TABLE Suppliers;
DROP DATABASE CSC123Lab2;
use group by and do filter in next level
with cte as
(select Suppliers.sid,avg(Catalog.cost) as avg_val
from Suppliers
left join Catalog on Suppliers.sid=Catalog.sid
group by Suppliers.sid
) select a.sid
from Catalog a join cte on a.sid=cte.sid
where a.cost>avg_val
I think you just want a window function:
select s.sid
from Suppliers s join
(select c.*, avg(c.cost) over () as avg_cost
from Catalog c
) c
on s.sid = c.sid
where c.cost > c.avg_cost;
Note, though, that you don't really need the left join. The where clause turns the left join into an inner join.
Then, you don't need the join at all, because sid is in both tables:
select c.sid
from (select c.*, avg(c.cost) over () as avg_cost
from Catalog c
) c
where c.cost > c.avg_cost;
If you prefer, you could express this using a subquery:
select c.sid
from Catalog c
where c.cost > (select avg(c2.cost) from catalog c2);

For every customer select all the other customers that bought the same item

Database description
I have a simple database composed of three tables: customer, product and custumer_product.
customer: Contains the information about the customer. His ID and name
product: Contains informations about the products that are available in the store. ID and name
custumer_product: junction table
- customer (table)
id integer primary key not null
name TEXT
- custumer_product (table)
id_product integer
id_customer integer
primary key(id_product, id_customer)
FOREIGN KEY(Id_product) REFERENCES product(id)
FOREIGN KEY (ID_customer) REFERENCES customer(ID)
- product (table)
id integer primary key not null
name TEXT
The three tables have been initialized in sqlfiddle by using SQLITE. The following SQL queries are used to construct the database
create table if not exists customer (id integer primary key not null, name TEXT);
create table if not exists product (id integer primary key not null, name TEXT);
create table if not exists customer_product (id_product integer, id_customer
integer, primary key(id_product, id_customer), FOREIGN KEY(Id_product) REFERENCES product(id), FOREIGN KEY (ID_customer) REFERENCES customer(ID));
insert into customer(id,name) values(1,"john");
insert into customer(id,name) values(2,"Paul");
insert into customer(id,name) values(3,"Jenny");
insert into customer(id,name) values(4,"Fred");
insert into customer(id,name) values(5,"Lea");
insert into product(id,name) values(1,"Mouse");
insert into product(id,name) values(2,"screen");
insert into product(id,name) values(3,"pc");
insert into product(id,name) values(4,"CD");
insert into product(id,name) values(5,"Game");
insert into customer_product values(1,1);
insert into customer_product values(1,2);
insert into customer_product values(1,3);
insert into customer_product values(2,1);
insert into customer_product values(2,2);
insert into customer_product values(2,3);
insert into customer_product values(3,4);
insert into customer_product values(4,5);
insert into customer_product values(5,5);
Problem
For every customer I want to select all the other customers that bought at least one similar product.
John and Paul bought at least 1 similar product
No customer bought a similar product as jenny yet
Fred and lea bought a similar product
output
"John" "Paul"
"Jenny"
"Fred" "Lea"
This is basically a self-join and possibly an aggregation. For instance, the following gets all customers that have purchased a similar product as another, ordered by the number of similar products:
select cp.id_customer, cp2.id_customer, count(*)
from customer_product cp join
customer_product cp2
on cp.id_product = cp2.id_product
group by cp.id_customer, cp2.id_customer
order by cp.id_customer, count(*) desc;
You can bring in additional information such as customer names by doing additional joins.
While I'm not entirely sure I understand the conditions, there are three basic steps to this problem, which you can combine into one query (or not).
Get the products that the customer bought
Get the IDs of the customers that bought the same products
Get the customer details based on those IDs
So for 1, you do a simple select:
SELECT id_product FROM customer_product WHERE id_customer = 1
For 2, you can use the IN statement:
SELECT * FROM customer_product WHERE id_product IN
(SELECT id_product FROM customer_product WHERE id_customer = 1);
For 3 use a combination of JOIN and GROUP BY to get the relevant details from the customer table.
first find the list of product bought by at least 2 customers, second find the name of the custumers using the join table and third select the customer's name once. here is the query:
select distinct c.name from(select c.name, p.name,cp.id_customer, cp.id_product from customer_product cp join customer c on c.id=cp.id_customer join product p on p.id=cp.id_customer where cp.id_product in(select id_product, total from(select id_product,count(*) as total from customer_product group by id_product)p where total>=2)p1)p2)

MySQL: How can this UNION be improved?

I have two tables, a for access and p for provider. I then have third table for joining the tables together, standard normalization. However, the provider table is a parent/child table, and the joining table has an option whether the access should be granted for all the provider children or not.
CREATE TABLE p (
p_id int PRIMARY KEY,
name varchar(32),
parent_id int,
FOREIGN KEY (parent_id) REFERENCES p(p_id)
);
CREATE TABLE a (
a_id int PRIMARY KEY,
name varchar(32)
);
CREATE TABLE ap (
a_id int,
p_id int,
sub tinyint,
FOREIGN KEY (a_id) REFERENCES a(a_id),
FOREIGN KEY (p_id) REFERENCES p(p_id)
);
Some sample data, 1 provider with 2 child providers. 2 access users, 1 with no child access and with child access.
INSERT INTO p VALUES(1, 'a', null);
INSERT INTO p VALUES(2, 'a.a', 1);
INSERT INTO p VALUES(3, 'a.b', 1);
INSERT INTO a VALUES(1, 'user 1');
INSERT INTO a VALUES(2, 'user 2');
INSERT INTO ap VALUES(1, 1, 0);
INSERT INTO ap VALUES(2, 1, 1);
The result is that I want to have a list of providers that the user have access to, based on the third table.
Currently I've solved this by joining two queries with UNION. The first query selects possible child providers and the second goes for primary providers.
SELECT p_id, name
FROM p
WHERE parent_id IN(
SELECT p_id FROM ap WHERE a_id = 1 AND sub = 1
)
UNION
SELECT ap.p_id, p.name
FROM ap
LEFT JOIN p ON p.p_id = ap.p_id
WHERE a_id = 1;
I don't like this query, it's ugly and there must be a smarter way :)
If I have the logic correct, then you want all records from p where one of the following is true:
p_id matches a record in ap for the given a_id.
parent_id matches a record in ap for a given a_id.
This suggests using exists for the conditions:
select p.p_id, p.name
from p
where exists (select 1
from ap
where ap.p_id = p.p_id and ap.a_id = 1
) or
exists (select 1
from ap
where ap.p_id = p.parent_id and ap.sub = 1 and ap.a_id = 1
)
With a composite index on ap(p_id, a_id, sub), this should have much better performance than your version of the query.

SQL: Detect duplicate customers

im trying to create a sql query, that will detect (possible) duplicate customers in my database:
I have two tables:
Customer with the columns: cid, firstname, lastname, zip. Note that cid is the unique customer id and primary key for this table.
IgnoreForDuplicateCustomer with the columns: cid1, cid2. Both columns are foreign keys, which references to Customer(cid). This table is used to say, that the customer with cid1 is not the same as the customer with the cid2.
So for example, if i have
a Customer entry with cid = 1, firstname="foo", lastname="anonymous" and zip="11231"
and another Customer entry with cid=2, firstname="foo", lastname="anonymous" and zip="11231".
So my sql query should search for customers, that have the same firstname, lastname and zip and the detect that customer with cid = 1 is the same as customer with cid = 2.
However, it should be possible to say, that customer cid = 1 and cid=2 are not the same, by storing a new entry in the IgnoreForDuplicateCustomer table by setting cid1 = 1 and cid2 = 2.
So detecting the duplicate customers work well with this sql query script:
SELECT cid, firstname, lastname, zip, COUNT(*) AS NumOccurrences
FROM Customer
GROUP BY fistname, lastname,zip
HAVING ( COUNT(*) > 1 )
My problem is, that i am not able, to integrate the IgnoreForDuplicateCustomer table, to that
like in my previous example the customer with cid = 1 and cid=2 will not be marked / queried as the same, since there is an entry/rule in the IgnoreForDuplicateCustomer table.
So i tried to extend my previous query by adding a where clause:
SELECT cid, firstname, lastname, COUNT(*) AS NumOccurrences
FROM Customer
WHERE cid NOT IN (
SELECT cid1 FROM IgnoreForDuplicateCustomer WHERE cid2=cid
UNION
SELECT cid2 FROM IgnoreForDuplicateCustomer WHERE cid1=cid
)
GROUP BY firstname, lastname, zip
HAVING ( COUNT(*) > 1 )
Unfortunately this additional WHERE clause has absolutely no impact on my result.
Any suggestions?
Here you are:
Select a.*
From (
select c1.cid 'CID1', c2.cid 'CID2'
from Customer c1
join Customer c2 on c1.firstname=c2.firstname
and c1.lastname=c2.lastname and c1.zip=c2.zip
and c1.cid < c2.cid) a
Left Join (
Select cid1 'CID1', cid2 'CID2'
From ignoreforduplicatecustomer one
Union
Select cid2 'CID1', cid1 'CID2'
From ignoreforduplicatecustomer two) b on a.cid1 = b.cid1 and a.cid2 = b.cid2
where b.cid1 is null
This will get you the IDs of duplicate records from customer table, which are not in table ignoreforduplicatecustomer.
Tested with:
CREATE TABLE IF NOT EXISTS `customer` (
`CID` int(11) NOT NULL AUTO_INCREMENT,
`Firstname` varchar(50) NOT NULL,
`Lastname` varchar(50) NOT NULL,
`ZIP` varchar(10) NOT NULL,
PRIMARY KEY (`CID`))
ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=100 ;
INSERT INTO `customer` (`CID`, `Firstname`, `Lastname`, `ZIP`) VALUES
(1, 'John', 'Smith', '1234'),
(2, 'John', 'Smith', '1234'),
(3, 'John', 'Smith', '1234'),
(4, 'Jane', 'Doe', '1234');
And:
CREATE TABLE IF NOT EXISTS `ignoreforduplicatecustomer` (
`CID1` int(11) NOT NULL,
`CID2` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `ignoreforduplicatecustomer` (`CID1`, `CID2`) VALUES
(1, 2);
Results for my test setup are:
CID1 CID2
1 3
2 3
Edit as per TPete's comment (dind't try it):
SELECT
C1.cid, C1.firstname, C1.lastname
FROM
Customer C1,
Customer C2
WHERE
C1.cid < C2.cid AND
C1.firstname = C2.firstname AND
C1.lastname = C2.lastname AND
C1.zip = C2.zip AND
CAST(C1.cid AS VARCHAR)+' ' +CAST(C2.cid AS VARCHAR) <>
(SELECT CAST(cid1 AS VARCHAR)+' '+CAST(cid2 AS VARCHAR) FROM IgnoreForDuplicateCustomer I WHERE I.cid1 = C1.cid AND I.cid2 = C2.cid);
Initially I thought that IgnoreForDuplicateCustomer was a field in the customer table.
crazy but I think it works :)
first I join the customer tables with itself on the names to get the duplicates
then I exclud the keys on the IgnoreForDuplicateCustomer table (the union is because the first query returns cid1, cid2 and cid2,cid1
the result will be duplicated but I think you can get the info you need
select c1.cid, c2.cid
from Customer c1
join Customer c2 on c1.firstname=c2.firstname
and c1.lastname=c2.lastname and c1.zip=c2.zip
and c1.cid!=c2.cid
except
(
select cid1,cid2 from IgnoreForDuplicateCustomer
UNION
select cid2,cid1 from IgnoreForDuplicateCustomer
)
second shot:
select firstname,lastname,zip from Customer
group by firstname,lastname,zip
having (count(*)>1)
except
select c1.firstname, c1.lastname, c1.zip
from Customer c1 join IgnoreForDuplicateCustomer IG on c1.cid=ig.cid1 join Customer c2 on ig.cid2=c2.cid
third:
select firstname,lastname,zip from (
select firstname,lastname,zip from Customer
group by firstname,lastname,zip
having (count(*)>1)
) X
where firstname not in (
select c1.firstname
from Customer c1 join IgnoreForDuplicateCustomer IG on c1.cid=ig.cid1 join Customer c2 on ig.cid2=c2.cid
)