SQL - find rows having n duplicate values - sql

Let's say I have a table like this:
OrderId | CustomerId | ProductName
======================================
73 | 301 | Sponge
74 | 508 | Garbage Bag
75 | 301 | Spoon
76 | 301 | Bacon
77 | 508 | Dog treats
78 | 301 | Paper
79 | 905 | Text book
and I want to find a customer who has made two orders in the past. How would I set up the query?
For the table above, the query would return the two rows for customer 508.
How would I modify it to return customers who have one previous order, so that it would return the row for customer 905?

select customerId, count(*)
from mytable
group by customerId
having count(*) >= 2

If you need only CustomerId of those who have exactly one order in table (they exist once) then the following query groups customers and counts how many times they appear in a table (here showing only those who appear once, modify as you wish).
SELECT
CustomerId
FROM
table
GROUP BY 1
HAVING COUNT(*) = 1
Let's say you want to list every customer and number of orders they've placed but no less than 2 then modify above query to add COUNT(*) in column list to be selected and the HAVING condition like that:
SELECT
CustomerId
COUNT(*) AS no_of_orders
FROM
table
GROUP BY 1
HAVING COUNT(*) > 1

I used a SQL query of something like that just yesterday.
I adapted it to your table, but I'm not 100% sure it will work.
CREATE TEMPORARY TABLE COMMANDS
SELECT OrderId, ProductName, COUNT(CustomerId) AS NbCmds
FROM your_table
GROUP BY OrderId;
SELECT CustomerId
FROM COMMANDS
WHERE NbCmds > 1;
Edit : You can also do it with a HAVING clause. Take a look here

Related

One one customer from table

I need help using Teradata SQL and I hope you can help.
I have a table that looks like this:
email | article number | discount | price
customer01#test.de | 123 | 15 | 999
customer01#test.de | 456 | 30 | 1999
customer01#test.de | 789 | 30 | 999
From this table I want only row from the customer which has the highest discount and (if there are multiple rows with the same discount) the lowest price.
So in the example above, I only want the 3rd line. How can I write a SQL query for this?
The most flexible way utilizes ROW_NUMBER:
select * from myTable
QUALIFY
ROW_NUMBER()
OVER (PARTITION BY email -- for each customer, otherwise remove it
ORDER BY discount DESC, price ASC) = 1
The simplest way to do this is via a simple select statement ordered by discount (descending) and then by price (ascending).
SELECT * FROM customers
ORDER BY discount DESC, price ASC
LIMIT 1
Use NOT EXISTS to return a row only if there are no other row with a higher discount, or another row with same discount and a lower price.
select *
from tablename t1
where not exists (select 1 from tablename t2
where t2.discount > t1.discount
or (t2.discount = t1.discount and t2.price < t1.price))

Access SQL query update calculation for duplicates

I have a query that filters results for products which have had orders sent after an user-input date, and calculates what the quantity becomes if the order was sent after that date.
SELECT *, [OnHand]+[OrderJoin.Quantity] AS Qty After
FROM Query3
WHERE (((Query3.ShippedDate)>[Enter End Date] And (Query3.ShippedDate) Is Not Null));
However, I need a way for it to recognise duplicates and update it based on those.
e.g. I have this
ID | Product Name | Qty Before | Qty Shipped | Qty After
11 | Chocolate | 80 | 20 | 100
11 | Chocolate | 80 | 10 | 90
And I'd need a way for it to show Qty After as 110 (after the 10 and 20 shipped)
If I understand correctly, you want an aggregation query. This would be something like this:
SELECT id, ProductName,
OnHand]+ SUM([OrderJoin.Quantity]) AS Qty After
FROM Query3
WHERE Query3.ShippedDate > [Enter End Date] And
Query3.ShippedDate) Is Not Null
GROUP BY id, ProductName, OnHand;
I note that OrderJoin is not defined, but that is the structure of your original query.

Oracle WITH clause and grouping by results

I have two tables: a product table and a territory table. The product tables holds IDs of products and the territory code denoting which countries they can be sold in:
PRODUCT:
PRODUCT_ID | TERRITORY_CODE
----------------------------
PROD1 | 2
PROD2 | 0
PROD3 | 1
PROD4 | 0
PROD5 | 2
PROD6 | 0
PROD7 | 2
The second table table holds a territory code and the corresponding ISO code of countries it's allowed to be sold in. For example:
TERRITORY:
TERRITORY_CODE | COUNTRY_CODE
---------------------------
0 | US
1 | CA
2 | US
2 | CA
I would like to write a query that counts the number of PRODUCT_IDs using COUNTRY_CODE as a key.
For example, I want to know how many distinct products there are for sale in the US. I don't want to have to know that 0 and 2 are territory codes that contain the US, I just want to look up by COUNTRY_CODE. How can I do this?
In some preliminary research, I've found that a WITH clause may be useful, and came up with the following query:
WITH country AS (
SELECT (DISTINCT COUNTRY_CODE)
FROM TERRITORY
)
SELECT COUNT(DISTINCT PRODUCT_ID)
FROM country c,
PRODUCT p
WHERE p.TERRITORY_CODE=c.TERRITORY_ID;
However, this doesn't produce the expected result. I also can't get it to group by COUNTRY_CODE. What am I doing wrong?
Looks like you need to use GROUP BY. Try something like this:
SELECT T.Country_Code, COUNT(DISTINCT PRODUCT_ID)
FROM Product P
JOIN Territory T ON P.Territory_Code = T.Territory_Code
GROUP BY T.Country_Code
And the SQL Fiddle.
Good luck.

SQL - Find Duplicates, then add to another table with count

There are ton's of listings on how to find duplicate rows, and remove them, or list out the duplicates. In the masses of responses i've tried searching through on here those are the only responses i've found. I figured I would just put up my question since its been an hour and still no luck.
This is the example data I have
Table Name: Customers
_____________________________
ID | CompanyName
--------------
1 | Joes
2 | Wendys
3 | Kellys
4 | Ricks
5 | Wendys
6 | Kellys
7 | Kellys
I need to be able to find all the duplicates in this table, then put the results into another table that lists what the company name is, and how many duplicates it found.
For example the above table I should have a new table that says something like
Table Name: CustomerTotals
_______________________________
ID | CompanyName | Totals
-------------------------------
1 | Joes | 1
2 | Wendys | 2
3 | Kellys | 3
4 | Ricks | 1
-----EDIT Added after 2 responses, ran into another question------
Thanks for the responses! What about the opposite? say i only want to add items to a new table "UniqueCustomers" from the Customers table that doesn't exist in CustomerTotals table?
Try this :
INSERT INTO CustomerTotals
(CompanyName, Totals)
SELECT CompanyName, COUNT(*)
FROM Customer
GROUP BY CompanyName
Use an identity column for the ID field.
for get the duplicates, you can do
Insert into CustomerTotals (Id, CompanyName, Totals)
Select min(Id), CompanyName, count(*) From Customers
group by CompanyName
there you got the results, conserving the minimun id for each company name(if you really need the first id from your original table, as I see in the results).
If not, you can use an Identity Column
If you only want the duplicates to be inserted into the second table, use this:
INSERT INTO CustomerTotals
(CompanyName, Totals)
SELECT CompanyName, COUNT(*)
FROM Customer
GROUP BY CompanyName
HAVING Count(*) > 1
The above examples are fine. But you should use count(1) instead of count(*) to improve performance.
Read this question.
I think below script is simplest...
SELECT CompanyName, COUNT(*) AS Total
INTO #tempTable
FROM Customer
GROUP BY CompanyName
HAVING Count(*) > 1

Select ID given the list of members

I have a table for the link/relationship between two other tables, a table of customers and a table of groups. a group is made up of one or more customers. The link table is like
APP_ID | GROUP_ID | CUSTOMER_ID
1 | 1 | 123
1 | 1 | 124
1 | 1 | 125
1 | 2 | 123
1 | 2 | 125
2 | 3 | 123
3 | 1 | 123
3 | 1 | 124
3 | 1 | 125
I now have a need, given a list of customer IDs to be able to get the group ID for that list of customer IDs. Group ID may not be unique, the same group ID will contain the same list of customer IDs but this group may exist in more than one app_id.
I'm thinking that
SELECT APP_ID, GROUP_ID, COUNT(CUSTOMER_ID) AS COUNT
FROM GROUP_CUST_REL
WHERE CUSTOMER_ID IN ( <list of ids> )
GROUP BY APP_ID, GROUP_ID
HAVING COUNT(CUSTOMER_ID) = <number of ids in list>
will return me all of the group IDs that contain all of the customer ids in the given list and only those group ids. So for a list of (123,125) only group id 2 would be returned from the above example
I will then have to link with the app table to use its created timestamp to identify the most recent application that the group existed in so that I can then pull the correct/most up to date info from the group table.
Does anyone have any thoughts on whether this is the most efficient way to do this? If there is another quicker/cleaner way I'd appreciate your thoughts.
This smells like a division:
Division sample
Other related stack overflow question
Taking a look at the provided links you'll see the solution to similar issues from relational alegebra's point of view, doesn't seem to be quicker and arguably cleaner.
I didn't look at your solution at first, and when I solved this I turned out to have solved this the same way you did.
Actually, I thought this:
<number of ids in list>
Could be turned into something like this (so that you don't need the extra parameter):
select count(*) from (<list of ids>) as t
But clearly, I was wrong. I'd stay with your current solution if I were you.