Counting the instances of customers - sql

Say that I have a table with one column named CustomerId.
The example of the instance of this table is :
CustomerId
14
12
11
204
14
204
I want to write a query that counts the number of occurences of customer IDs.
At the end, I would like to have a result like this :
CustomerId NumberOfOccurences
14 2
12 1
11 1
204 2
14 1
I cannot think of a way to do this.

This is the most basic example of GROUP BY
SELECT CustomerId, count(*) as NumberOfOccurences
FROM tablex GROUP BY CustomerId;

Practice exercise #3 on this page explains how to do this.
CREATE TABLE customers
( customer_id number(10) not null,
customer_name varchar2(50) not null,
city varchar2(50),
CONSTRAINT customers_pk PRIMARY KEY (customer_id)
);
INSERT INTO customers (customer_id, customer_name, city)
VALUES (7001, 'Microsoft', 'New York');
INSERT INTO customers (customer_id, customer_name, city)
VALUES (7002, 'IBM', 'Chicago');
INSERT INTO customers (customer_id, customer_name, city)
VALUES (7003, 'Red Hat', 'Detroit');
INSERT INTO customers (customer_id, customer_name, city)
VALUES (7004, 'Red Hat', 'New York');
INSERT INTO customers (customer_id, customer_name, city)
VALUES (7005, 'Red Hat', 'San Francisco');
INSERT INTO customers (customer_id, customer_name, city)
VALUES (7006, 'NVIDIA', 'New York');
INSERT INTO customers (customer_id, customer_name, city)
VALUES (7007, 'NVIDIA', 'LA');
INSERT INTO customers (customer_id, customer_name, city)
VALUES (7008, 'NVIDIA', 'LA');
Solution:
The following SQL statement would return the number of distinct cities for each customer_name in the customers table:
SELECT customer_name, COUNT(DISTINCT city) as "Distinct Cities"
FROM customers
GROUP BY customer_name;
It would return the following result set:
CUSTOMER_NAME Distinct Cities
IBM 1
Microsoft 1
NVIDIA 2
Red Hat 3

Related

Oracle. apply Conditional ordering. If >=2 rows have duplicate data, those rows must follow a seperate condition to those that don't have duplicates

Select custno, custname, location
From customer
Order by
The order of the results have to fit the following criteria:
custno, custnames and location in ascending location sequence. If 2 or more rows have the same location, list only those rows in ascending custname sequence.
I don't even know where to begin with the 2nd part of the question.
I found questions somewhat similar to this and it was advised to use case with when, but I've never used that before, and not sure what to begin. Here's where I'm at so far
Select custno, custname, location
From customer
Order by
Case
when count(location) >= 2
then custname asc
else location asc
end
This is the pic of the results they provided.
And the statements that was provided.
create table GRADE (
gradeID varchar2(2),
description varchar2(20),
Primary Key (gradeID) );
create table TYPE (
TypeCode number,
Title varchar2(20),
gradeID varchar2(2),
category varchar2(1),
Primary Key (TypeCode),
Foreign Key (gradeID) references GRADE );
create table customer(
custno number,
custname varchar2(20),
typecode number,
sales number(7,2),
location varchar2(20),
Primary Key (custno),
Foreign Key (typecode) references TYPE );
Insert into grade (gradeID,description) values ('WC','Women and
Children');
Insert into grade (gradeID,description) values ('M','Men');
Insert into TYPE (TypeCode,Title,gradeID,category) values (1,'Under
20','WC','X');
Insert into TYPE (TypeCode,Title,gradeID,category) values (2,'Under
20','M','Z');
Insert into TYPE (TypeCode,Title,gradeID,category) values (3,'20
plus','WC','Z');
Insert into TYPE (TypeCode,Title,gradeID,category) values (4,'20
plus','M','X');
Insert into TYPE (TypeCode,Title,gradeID,category) values
(5,'Special','M','S');
Insert into customer (custno, custname, TypeCode,sales,location) values
(21,'Wendy',1,300,'Haw');
Insert into customer (custno, custname, TypeCode,sales,location) values
(24,'Sue',3,700,'Haw');
Insert into customer (custno, custname, TypeCode,sales,location) values
(27,'Nick',2,NULL,'Kew');
Insert into customer (custno, custname, TypeCode,sales,location) values
(22,'Dave',4,95,'Richmond');
Insert into customer (custno, custname, TypeCode,sales,location) values
(25,'Jenny',1,525,'Haw');
Insert into customer (custno, custname, TypeCode,sales,location) values
(29,'Bob',4,15,'Kew');
Insert into customer (custno, custname, TypeCode,sales,location) values
(23,'Helen',3,200,'Haw');
Insert into customer (custno, custname, TypeCode,sales,location) values
(28,'Linda',1,25,'Kew');
Insert into customer (custno, custname, TypeCode,sales,location) values
(26,'Xena',3,Null, 'Richmond');
Start with a query that returns nr of identical rows, then select only rows with nr > 1:
select ...
from customer c,
(
Select count(*) nr, location
From customer
Group by location
) n
where n.nr > 1
and c.l = n.l
This isn't a complete query, but you get the idea. It is hard for me to get this exactly right without having your table.

Returning identity of INSERT for new INSERT with data outside of RETURNING clause

I'm using PostgreSQL 12.3.
Similar to the many questions that have been asked about this, like this one, but I need to use data from another table that isn't present in the RETURNING clause.
For a contrived example, consider three tables: customers, products, and sales, and a scenario where a customer needs to be created at the point of sale, and the sales table needs to be updated with both the users and products ids.
CREATE TABLE public.customers (
id SERIAL PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL
)
CREATE TABLE public.products (
id SERIAL PRIMARY KEY,
product TEXT NOT NULL
)
CREATE TABLE public.sales (
id SERIAL PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers(id),
product_id INTEGER NOT NULL REFERENCES products(id)
)
INSERT INTO customers (first_name, last_name) VALUES ('Bob', 'Smith');
INSERT INTO customers (first_name, last_name) VALUES ('Jane', 'Doe');
INSERT INTO products (product) VALUES ('widget 1');
INSERT INTO products (product) VALUES ('widget 2');
INSERT INTO products (product) VALUES ('widget 3');
INSERT INTO sales (customer_id, product_id) VALUES (1, 1);
INSERT INTO sales (customer_id, product_id) VALUES (2, 1);
INSERT INTO sales (customer_id, product_id) VALUES (2, 2);
If I just need the customer id, the following wouldn't be a problem:
WITH new_customer_and_new_sale AS (
INSERT INTO customers (first_name, last_name) VALUES ('John', 'Doe') RETURNING id
)
INSERT INTO sales (customer_id)
SELECT id FROM new_user_and_new_sale
Since sales has constraints not found in the returning clause, the above obviously won't work. I've tried joining tables to pull in the additional data, but haven't been able to get it to work.
Please overlook any minor issues you may have with the structure of the tables, as the data I'm working with has hundreds of columns and many foreign keys. I've tried to condense the problem into its simplest form, at the risk of seeming contrived.
Your example fails because you're not providing the value for product_id, which is required.
You can directly specify one like this:
WITH inserted_customer AS (
INSERT INTO customers (first_name, last_name) VALUES ('acacaca', 'Doe') RETURNING id
)
INSERT INTO sales (customer_id, product_id)
SELECT inserted_customer.id, 2 FROM inserted_customer;
If you want to get the product ID from an existing product you can do it with a subquery (or a CTE if you're doing more complicated stuff).
WITH inserted_customer AS (
INSERT INTO customers (first_name, last_name) VALUES ('acacaca', 'Doe') RETURNING id
)
INSERT INTO sales (customer_id, product_id)
SELECT inserted_customer.id, (SELECT id FROM products ORDER BY id DESC LIMIT 1) FROM inserted_customer;
If you want to insert the customer and the product on the fly, you can do two CTEs:
WITH inserted_customer AS (
INSERT INTO customers (first_name, last_name) VALUES ('acacaca', 'Doe') RETURNING id
),
inserted_product AS (
INSERT INTO products (product) VALUES ('my product') RETURNING id
)
INSERT INTO sales (customer_id, product_id)
SELECT inserted_customer.id, inserted_product.id
FROM inserted_customer, inserted_product;
Hope this helps!

sql- Number of actual records added

I am trying to generate a report based on counselling and actual to see how many counseling were converted to actual.
I have table which has Patient, Booking Category, Doctor, Booking.
SQL Fiddle
Following are the business rules
Fetch all the bookings made by patients if they made booking after counseling
The user can take counseling booking first and book one or more bookings that falls under the same counselling group. Example: They can do a first booking Counseling Dental then can book anything mapped to that group. i. e Dentail surgery and Teeth repair. These information maintained in CounselingXActualBookingCategoryMap table
If patient book more than one actual booking consider only one, which is not cancelled
If counselling is cancelled dont consider.
If actual is cancelled dont consider.
Get a total number of counseling bookings(it need not to be a actual booking doctor) and actual bookings for each doctor. Any one can be a counseling doctor. But report we consider only the doctor who did actual
Here is the SQL i tried. But its taking all records instead of one actual for that group.
SELECT P.Name As Patient, SurgeryB.BookingId, SurgeryB.BookingDate, C.CategoryName,
d.name as doctor
FROM BOOKING CounsB
INNER JOIN BOOKING SurgeryB
ON CounsB.PatientId = SurgeryB.PatientId AND ISNULL(SurgeryB.IsCancelled,0)=0
INNER JOIN CounselingXActualBookingCategoryMap MAP
ON MAP.CounselingCategoryId = CounsB.CategoryId
AND MAP.ActualBookingCategoryId = SurgeryB.CategoryId
AND SurgeryB.BookingDate > CounsB.BookingDate
INNER JOIN PATIENT P ON P.PATIENTID = SurgeryB.PATIENTID
inner join category c on c.categoryid= SurgeryB.CategoryId
inner join doctor d on SurgeryB.doctorid = d.doctorid
WHERE ISNULL(CounsB.IsCancelled,0)=0
order by p.patientid
Issue:
I do not want to see a record that Alex made booking for Teeth repair, since he already did actual for same group Dental and category Dental Surgery
I want to get counseling and actual made bookings. Example 100 counseling made and only 70 actual booked like that for each counseling category.
I have added to your code as below:
SELECT P.Name As Patient, SurgeryB.BookingId, SurgeryB.BookingDate, C.CategoryName, map.GroupId, map.CounselingCategoryId, map.ActualBookingCategoryId,
d.name as doctor
into #temp
FROM BOOKING CounsB
INNER JOIN BOOKING SurgeryB
ON CounsB.PatientId = SurgeryB.PatientId AND ISNULL(SurgeryB.IsCancelled,0)=0
INNER JOIN CounselingXActualBookingCategoryMap MAP
ON MAP.CounselingCategoryId = CounsB.CategoryId
AND MAP.ActualBookingCategoryId = SurgeryB.CategoryId
AND SurgeryB.BookingDate > CounsB.BookingDate
INNER JOIN PATIENT P ON P.PATIENTID = SurgeryB.PATIENTID
inner join category c on c.categoryid= SurgeryB.CategoryId
inner join doctor d on SurgeryB.doctorid = d.doctorid
WHERE ISNULL(CounsB.IsCancelled,0)=0
order by p.patientid
;with cte as
(
select Patient, BookingId, BookingDate, CategoryName, Doctor, ROW_NUMBER() over (partition by Patient, GroupId order by BookingDate) row_num
from #temp t
)
select Patient, BookingId, BookingDate, CategoryName, Doctor from cte where row_num = 1
drop table #temp
HTH!
I have an answer to the query you gave as an example, which is described in business rule 1 and to the one in business rule 6.
I made some slight changes to your tables, since I had to re-create them to test the query anyway.
create table patient
(
id int,
name varchar(8)
);
create table doctor
(
id int,
name varchar(8)
);
create table category
(
id int,
name varchar(20),
counseling_or_surgery varchar(10)
);
create table map
(
counseling_category_id int,
surgery_category_id int,
group_id int
);
create table booking
(
id int,
patient_id int,
category_id int,
doctor_id int,
booking_date date,
cancelled bit
);
Here are the inserts to set up the data:
insert into patient (id, name) values (1, 'Alex');
insert into patient (id, name) values (2, 'John');
insert into patient (id, name) values (3, 'Mark');
insert into patient (id, name) values (4, 'Stephen');
insert into doctor (id, name) values (1, 'Doctor 1');
insert into doctor (id, name) values (2, 'Doctor 2');
insert into doctor (id, name) values (3, 'Doctor 3');
insert into category (id, name, counseling_or_surgery) values (1, 'Counseling Dental', 'Counseling');
insert into category (id, name, counseling_or_surgery) values (2, 'Counseling Nose', 'Counseling');
insert into category (id, name, counseling_or_surgery) values (3, 'Dental surgery', 'Surgery');
insert into category (id, name, counseling_or_surgery) values (4, 'Teeth repair', 'Surgery');
insert into category (id, name, counseling_or_surgery) values (5, 'Nose Surgery', 'Surgery');
insert into category (id, name, counseling_or_surgery) values (6, 'Nose adjustment', 'Surgery');
insert into map (counseling_category_id, surgery_category_id, group_id) values (1, 3, 1);
insert into map (counseling_category_id, surgery_category_id, group_id) values (1, 4, 1);
insert into map (counseling_category_id, surgery_category_id, group_id) values (2, 5, 2);
insert into map (counseling_category_id, surgery_category_id, group_id) values (2, 6, 2);
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values ( 1, 1, 1, 1, '2017-11-20', 'false');
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values ( 2, 1, 3, 3, '2017-11-25', 'false');
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values ( 3, 1, 4, 2, '2017-11-25', 'false');
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values ( 4, 1, 2, 1, '2017-11-21', 'true');
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values ( 5, 1, 2, 2, '2017-11-26', 'false');
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values ( 6, 1, 5, 3, '2017-11-28', 'false');
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values ( 7, 3, 2, 2, '2017-11-26', 'false');
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values ( 8, 3, 6, 2, '2017-11-26', 'true');
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values ( 9, 4, 2, 2, '2017-11-29', 'false');
insert into booking (id, patient_id, category_id, doctor_id, booking_date, cancelled) values (10, 4, 5, 1, '2017-11-29', 'false');
Given these tables, here is the query for business rule 1:
select
c.name as patient,
b.id as booking_id,
b.booking_date as first_surgery_date,
d.name as first_surgery,
e.name as doctor
from
(
select
r.patient_id,
min(r.id) as booking_id,
t.group_id
from
booking r
join
category s
on r.category_id = s.id
join
map t
on t.surgery_category_id = r.category_id
where
r.cancelled = 0 and
s.counseling_or_surgery = 'Surgery'
group by
r.patient_id,
t.group_id
) a
join
booking b
on a.booking_id = b.id
join
patient c
on b.patient_id = c.id
join
category d
on b.category_id = d.id
join
doctor e
on b.doctor_id = e.id;
and the results are:
patient booking_id first_surgery_date first_surgery doctor
---------------- ----------- ------------------ ---------------- ----------------
Stephen 10 2017-11-29 Nose Surgery Doctor 1
Alex 2 2017-11-25 Dental surgery Doctor 3
Alex 6 2017-11-28 Nose Surgery Doctor 3
(3 rows affected)
Here's the query for business rule 6. It counts cancellations too; easy to change if that's not what you want.
select
z.name as doctor,
y.total_counseling_bookings,
x.total_surgery_bookings
from
(
select
doctor_id,
count(*) as total_surgery_bookings
from
booking a
join
category b
on a.category_id = b.id
where
b.counseling_or_surgery = 'Surgery'
group by
doctor_id
) x
full outer join
(
select
doctor_id,
count(*) as total_counseling_bookings
from
booking c
join
category d
on c.category_id = d.id
where
d.counseling_or_surgery = 'Counseling'
group by
doctor_id
) y
on x.doctor_id = y.doctor_id
join
doctor z
on x.doctor_id = z.id
and here are the results for this one:
doctor total_counseling_bookings total_surgery_bookings
-------- ------------------------- ----------------------
Doctor 1 2 1
Doctor 2 3 2
Doctor 3 NULL 2
(3 rows affected)

SQL INSERT INTO with subquery and value

Is there a way I can use a combination of hard values and a subquery to insert into a table with one command?
For example:
INSERT INTO suppliers (supplier_id, supplier_name, supplier_type)
SELECT account_no, name
FROM customers
WHERE city = 'San Diego';
I need supplier_type to be 3. So can I do the following for the second line?
SELECT account_no, name, supplier_type = 3
supplier_type is not in the customers table
Just add it with your SELECT fields.
INSERT INTO suppliers (supplier_id, supplier_name, supplier_type)
SELECT account_no, name, 3 AS supplier_type
FROM customers
WHERE city = 'San Diego';
Even simpler, just fill in the field with the value, dont even need an AS:
INSERT INTO suppliers (supplier_id, supplier_name, supplier_type)
SELECT account_no, name, 3
FROM customers
WHERE city = 'San Diego';

SQL Nested Aggregate Query- How do I get the number of customers per employee?

The following is the prompt I need to answer:
List the number of customers for each employee. Include employee's name and number of
customers labeled appropriately, listing the employee with the most customers first.
The following is my EMPLOYEES table:
create table EMPLOYEES
(EmpID char(4) unique Not null,
Ename varchar(10),
Job varchar(9),
MGR char(4),
Hiredate date,
Salary decimal(7,2),
Comm decimal(7,2),
DeptNo char(2) not null,
Primary key(EmpID),
Foreign key(DeptNo) REFERENCES DEPARTMENTS(DeptNo));
insert into EMPLOYEES values (7839,'King','President',null,'17-Nov-11',5000,null,10);
insert into EMPLOYEES values (7698,'Blake','Manager',7839,'01-May-11',2850,null,30);
insert into EMPLOYEES values (7782,'Clark','Manager',7839,'02-Jun-11',2450,null,10);
insert into EMPLOYEES values (7566,'Jones','Manager',7839,'02-Apr-11',2975,null,20);
insert into EMPLOYEES values (7654,'Martin','Salesman',7698,'28-Feb-12',1250,1400,30);
insert into EMPLOYEES values (7499,'Allen','Salesman',7698,'20-Feb-11',1600,300,30);
insert into EMPLOYEES values (7844,'Turner','Salesman',7698,'08-Sep-11',1500,0,30);
insert into EMPLOYEES values (7900,'James','Clerk',7698,'22-Feb-12',950,null,30);
insert into EMPLOYEES values (7521,'Ward','Salesman',7698,'22-Feb-12',1250,500,30);
insert into EMPLOYEES values (7902,'Ford','Analyst',7566,'03-Dec-11',3000,null,20);
insert into EMPLOYEES values (7369,'Smith','Clerk',7902,'17-Dec-10',800,null,20);
insert into EMPLOYEES values (7788,'Scott','Analyst',7566,'09-Dec-12',3000,null,20);
insert into EMPLOYEES values (7876,'Adams','Clerk',7788,'12-Jan-10',1100,null,20);
insert into EMPLOYEES values (7934,'Miller','Clerk',7782,'23-Jan-12',1300,null,10);
The following is my CUSTOMERS table:
create table CUSTOMERS
(CustID char(6) unique Not null,
Name varchar(45),
Address varchar(40),
City varchar(30),
State varchar(2),
Zip varchar(9),
AreaCode char(3),
Phone varchar (9),
RepID char(4) not null,
CreditLimit decimal(9,2),
Primary key(CustID),
Foreign key(RepID) References EMPLOYEES(EmpID));
insert into CUSTOMERS values (100,'Jocksports','345 Viewridge','Belmont','CA','96711',415,'598-6609',7844,5000);
insert into CUSTOMERS values (101,'TKB Sport Shop','490 Boli Rd.','Redwood City','CA','94061',415,'368-1223',7521,10000);
insert into CUSTOMERS values (102,'Vollyrite','9722 Hamilton','Burlingame','CA','95133',415,'644-3341',7654,7000);
insert into CUSTOMERS values (103,'Just Tennis','Hillview Mall','Burlingame','CA','97544',415,'677-9312',7521,3000);
insert into CUSTOMERS values (104,'Every Mountain','574 Surry Rd.','Cupertino','CA','93301',408,'996-2323',7499,10000);
insert into CUSTOMERS values (105,'K + T Sports','3476 El Paseo','Santa Clara','CA','91003',408,'376-9966',7844,5000);
insert into CUSTOMERS values (106,'Shape Up','908 Sequoia','Palo Alto','CA','94301',415,'364-9777',7521,6000);
insert into CUSTOMERS values (107,'Womens Sports','Valco Village','Sunnyvale','CA','93301',408,'967-4398',7499,10000);
insert into CUSTOMERS values (108,'North Woods Fitness Supply Center','98 Lone Pine Way','Hibbing','MN','55649',612,'566-9123',7844,8000);
The following is my query:
select ename, empId
from EMPLOYEES
where EmpID in
(select count(repid) as NumberOfCustomers
from CUSTOMERS
group by RepID);
Why is my query not working?
I know I want to match the empid from EMPLOYEES to the repID in CUSTOMERS and then COUNT how many times the rep ID shows up in CUSTOMERS. The only reason I need the EMPLOYEES table is to out put Ename. Im confused about the syntaxt I need to use because I need to output the count of RepID in the CUSTOMERS table
You can also use Common Table Expression if you are using SQL Server 2005 and above.
;WITH CTE
AS
(
SELECT RepID, COUNT(*) AS CNT
FROM CUSTOMERS
GROUP BY REPID
)
SELECT E.Ename, E.EmpID, ISNULL(C.CNT, 0)
FROM EMPLOYEES E
LEFT OUTER JOIN CTE C ON C.RepID = E.EmpID
DEMO
SELECT *
FROM employees e
CROSS APPLY
(
SELECT COUNT(*)
FROM customers c
WHERE c.repId = e.empId
) cc (cnt)
ORDER BY
cnt DESC
See this on SQLFiddle
The same with a subquery:
SELECT *,
(
SELECT COUNT(*)
FROM customers c
WHERE c.repId = e.empId
) cnt
FROM employees e
ORDER BY
cnt DESC
Your inner query only has a count(repid), which is a count, not the actual EmployeeID that your outer query requires in where EmpID in (xxx). Not sure why're you want a count in your inner query, because you'll lose it in the final result, but this should work:
select ename, empId
from EMPLOYEES
where EmpID in (
select repID
from CUSTOMERS);
What about this? or did i misunderstand
SELECT ename, count(*) as NumCustomers
FROM Customers INNER JOIN
Employees ON customers.repid = employees.empid GROUP BY repid,ename
ORDER BY numCustomers DESC