SQL Check is there different records in table - sql

I want to check if there are any different records in my table. I have a sales table and in this table I have 2 records for same product so actually this salesman doesn't sale more than one product. I need a select query to check salesmen who sell more than 1 (different) product.
Table name SALES -- columns sales_id, salesman_name, product,name, quantity
Need only show salesman names.
Example data and expectation

You can use COUNT(DISTINCT <Field Name>) for what you want. (same for sqlserver, MySQL and Oracle)
Check this query:
SELECT salesman_name
,COUNT(DISTINCT product) ProductCount
FROM Sales
GROUP BY salesman_name
HAVING COUNT(DISTINCT product) >1

SELECT *
FROM SALES
WHERE salesman_name IN (
SELECT
salesman_name
FROM SALES
GROUP BY product
HAVING COUNT(*) > 1
)

Just use aggregation:
select salesman_name
from sales
group by salesman_name
having min(product) <> max(product);
If you want the original rows use exists:
select s.*
from sales s
where exists (select 1
from sales s2
where s2.salesman_name = s.salesman_name and
s2.product <> s.product
);
With an index on sales(salesman_name, product), this should be the fastest way to get the original rows.

SELECT
salesman_name,product,COUNT(*)
FROM
SALES
GROUP BY
salesman_name,product
HAVING
COUNT(*) > 1

Related

Best approach to display all the users who have more than 1 purchases in a month in SQL

I have two tables in an Oracle Database, one of which is all the purchases done by all the customers over many years (purchase_logs). It has a unique purchase_id that is paired with a customer_id.The other table contains the user info of all the customers. Both have a common key of customer_id.
I want to display the user info of customers who have more than 1 unique item (NOT the item quantity) purchased in any month (i.e if A customer bought 4 unique items in february 2020 they would be valid as well as someone who bought 2 items in june). I was wondering what should my correct approach be and also how to correct execute that approach.
The two approaches that I can see are
Approach 1
Count the overall number of purchases done by all customers, filter the ones that are greater than 1 and then check if they any of them were done within a month.
Use this as a subquery in the where clause of the main query for retrieving the customer info for all the customer_id which match this condition.
This is what i've done so far,this retrieves the customer ids of all the customers who have more than 1 purchases in total. But I do not understand how to filter out all the purchases that did not occur in a single arbitrary month.
SELECT * FROM customer_details
WHERE customer_id IN (
SELECT cust_id from purchase_logs
group by cust_id
having count(*) >= 2);
Approach 2
Create a temporary table to Count the number of monthly purchases of a specific user_id then find the MAX() of the whole table and check if that MAX value is bigger than 1 or not. Then if it is provide it as true for the main query's where clause for the customer_info.
Approach 2 feels like the more logical option but I cannot seem to understand how to write the proper subquery for it as the command MAX(COUNT(customer_id)) from purchase_logs does not seem to be a valid query.
This is the DDL diagram.
This is the Sample Data of Purchase_logs
Customer_info
and Item_info
and the expected output for this sample data would be
It is certainly possible that there is a simpler approach that I am not seeing right now.
Would appreciate any suggestions and tips on this.
You need this query:
SELECT DISTINCT cust_id
FROM purchase_logs
GROUP BY cust_id, TO_CHAR(purchase_date, 'YYYY-MON')
HAVING COUNT(DISTINCT item_id) > 1;
to get all the cust_ids of the customers who have more than 1 unique item purchased in any month and you can use with the operator IN:
SELECT *
FROM customer_details
WHERE customer_id IN (
SELECT DISTINCT cust_id -- here DISTINCT may be removed as it does not make any difference when the result is used with IN
FROM purchase_logs
GROUP BY cust_id, TO_CHAR(purchase_date, 'YYYY-MON')
HAVING COUNT(DISTINCT item_id) > 1
);
One approach might be to try
with multiplepurchase as (
select customer_id,month(purchasedate),count(*) as order_count
from purchase_logs
group by customer_id,month(purchasedate)
having count(*)>=2)
select customer_id,username,usercategory
from mutiplepurchase a
left join userinfo b
on a.customer_id=b.customer_id
Expanding on #MT0 answer:
SELECT *
FROM customer_details CD
WHERE exists (
SELECT cust_id
FROM purchase_logs PL
where CD.customer_id = PL.customer_id
GROUP BY cust_id, item_id, to_char(purchase_date,'YYYYMM')
HAVING count(*) >= 2
);
I want to display the user info of customers who have more than 1 purchases in a single arbitrary month.
Just add a WHERE filter to your sub-query.
So assuming that you wanted the month of July 2021 and you had a purchase_date column (with a DATE or TIMESTAMP data type) in your purchase_logs table then you can use:
SELECT *
FROM customer_details
WHERE customer_id IN (
SELECT cust_id
FROM purchase_logs
WHERE DATE '2021-07-01' <= purchase_date
AND purchase_date < DATE '2021-08-01'
GROUP BY cust_id
HAVING count(*) >= 2
);
If you want the users where they have bought two-or-more items in any single calendar month then:
SELECT *
FROM customer_details c
WHERE EXISTS (
SELECT 1
FROM purchase_logs p
WHERE c.customer_id = p.cust_id
GROUP BY cust_id, TRUNC(purchase_date, 'MM')
HAVING count(*) >= 2
);

sql deleting duplicate row

I have a table in SQL
Id owner_id amount
1 100 1000
2 101 2000
3 100 3000
4 104 800
5 100 1200
i want only one owner_id i don't want 100 multiple times, but i want amount of all owner_id 100 i,e that amount should be added(i,e. 1000+3000+12000) if i delete duplicate Owner_id row. how to do it
And one more issue that owner_id from another table, how to get Owner name from another table. How to add join to get name of the owner
SELECT
owner_id,
SUM(amount) total_amount
FROM
table
GROUP BY
owner_id
try this :
-- Acumulate all the amount to be able to do the cleanup
UPDATE table SET amount = sumAmount
FROM table t
JOIN (SELECT owner_id, SUM(amount) sumAmount
FROM table
GROUP BY owner_id) x ON x.owner_id = t.owner_id;
-- Delete duplicated data
WITH CTE AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY owner_id, amount ORDER BY Id) row
FROM table)
DELETE CTE WHERE row <> 1
Please use below query,
select owner_id, sum(amount) from table_name group by owner_id;
It works with the SUM Function, here is a reference: Link
SUM sums the amount of a the column which you insert, here: amount.
Please be aware that some functions only works if all other selected columns within another function OR grouped by.
SELECT
owner_id,
SUM(amount) total_amount
FROM
table
GROUP BY
owner_id

Show duplicate rows(all columns of that row) where all columns are duplicate except one column

In below table, I need to select duplicate records where all columns are duplicate except Customer Type and Price for a particular week.
For e.g
Week Customer Product Customer Type Price
1 Alex Cycle Consumer 100
1 Alex Cycle Reseller 101
2 John Motor Consumer 200
3 John Motor Consumer 200
3 John Motor Reseller 201
I am using below query but this query doesn't show me both costumer type, it just shows me consumer count(*) for a combination.
select Week, Customer, product, count(distinct Customer Type)
from table
group by Week, Customer, product
having count(distinct Customer Type) > 1
I would like to see below result, that shows me duplicate values and not just the count(*) of duplicate row. I am trying to see customers assigned to multiple customer types in a particular week for a product and at the same time show me all columns. It doesn't matter if the price is different.
Week Customer Product Customer Type Price
1 Alex Cycle Consumer 100
1 Alex Cycle Reseller 101
3 John Motor Consumer 200
3 John Motor Reseller 201
Thanks
Shaki
WITH CustomerDistribution_CTE (WeekC ,CustomerC, ProductC)
AS
(
select Week, Customer, product
from Your_Table_Name group by Week, Customer,
product having count(distinct CustomerType) > 1
)
SELECT Y.*
FROM CustomerDistribution_CTE C
inner join Your_Table_Name Y on C.WeekC =Y.Week
and C.CustomerC =Y.Customer and C.productC =Y.product
Note :Please replace "Your_Table_Name" with exact table name and Try.
One way to achieve this, using generic SQL, is to use a "derived table" like this:
select x.*
from tablex x
inner join (
select Week, Customer, Product
from tablex
group by Week, Customer, Product
having count(*) > 1
) d on x.Week = d.Week and x.Customer = d.Customer and x.Product = d.Product
You can do that by using DISTINCT like
select DISTINCT Customer,Product,Customer_Type,Price from Your_Table_Name
will look for DISTINCT combination.
Note: This query if of SQL Server
From the expected result that you have pasted, it looks like you are not concerned about the week.
If you have a ID (incremental PK), it would be much simpler like below
select * from table where ID not in
(select max(ID) from table group by Customer, Product, CustomerType having count(*) > 1 )
This is tested on MySQL. Do you have a ID column?
In case you don't have a ID column, try the below:
select max(week) week, Customer, Product, CustomerType, max(price) from device group by Customer, Product, CustomerType;
I have not verified this one.
This will return your expected result set:
select *
from table
-- Teradata syntax to filter the result of an OLAP-function
-- (similar to HAVING after GROUP BY)
qualify
count(*)
over (partition by Week, Customer, product) > 1
For other DBMSes you will need to nest your query:
select *
from
(
select ...,
count(*)
over (partition by Week, Customer, product) as cnt
from table
) as dt
where cnt > 1
Edit:
After re-reading your description above Select might be not exactly what you want, because it will also return rows with a single type. Then switch to:
select *
from table
-- Teradata syntax to filter the result of an OLAP-function
-- (similar to HAVING after GROUP BY)
qualify -- at least two different types:
min(Customer_Type) over (partition by Week, Customer, product)
<> max(Customer_Type) over (partition by Week, Customer, product)

Computed Column in Select Query?

I Want To Create A %Share Column Whose Values Are Derived By Dividing The Sale Of Each Customer With The Total Sale. I'm Using The Below Query But Get Error That Column 'Sale' Cannot Be Found. Is there Is A Way Through Which I Can Get Total Of Sale Column i.e. 600 ? Please Help ...
Select IsNull([Customer].[FirstName],'Total') as Customer,
format(Sum([MY_DB].[dbo].[Order].[TotalAmount]),'0.00') [Sale],
FORMAT(sum([MY_DB].[dbo].[Order].[TotalAmount])/ sum([Sale]),'0.00%') as 'Share%'
From Customer
INNER JOIN [MY_DB].[dbo].[Order]
ON [Customer].[Id]=[MY_DB].[dbo].[Order].[CustomerId]
Group By [Customer].[FirstName] with Rollup
Having (Sum([MY_DB].[dbo].[Order].[TotalAmount]) > (Select AVG([MY_DB].[dbo].[Order].[TotalAmount]) From [MY_DB].[dbo].[Order]))
Order By [Customer].[FirstName] Desc;
-
Desired Result:
Customer Sale %Share
Zbyszek 100 16.66 %
Yvonne 200 33.33 %
Yoshi 300 50.00 %
You have to modify the existing query quite a bit. I don't think you need with rollup.
For getting the total sales use sum() over(). Then divide each sale amount by the total to get the percentage. In the same way, using avg() over() you can compute the average and find customers with sales >= avgamount.
Select Customer,[Sale],[Share%]
from (
Select Distinct
c.[FirstName] as Customer,
format(sum(o.[TotalAmount]) over(partition by o.[CustomerId]),'0.00') as [Sale],
format(100.0*sum(o.[TotalAmount]) over(partition by o.[CustomerId]) / sum(o.[TotalAmount]) over(),'0.00%') as 'Share%',
AVG(o.[TotalAmount]) over() as 'AvgAmount'
From Customer c
INNER JOIN [MY_DB].[dbo].[Order] o ON c.[Id]=o.[CustomerId]
) t
Where Sale >= AvgAmount
Order By Customer Desc;
Without computing the average you can just check for customers with share >= 50%.
Select Customer,[Sale],[Share%]
from (
Select Distinct
c.[FirstName] as Customer,
format(sum(o.[TotalAmount]) over(partition by o.[CustomerId]),'0.00') as [Sale],
format(100.0*sum(o.[TotalAmount]) over(partition by o.[CustomerId]) / sum(o.[TotalAmount]) over(),'0.00%') as 'Share%'
From Customer c
INNER JOIN [MY_DB].[dbo].[Order] o ON c.[Id]=o.[CustomerId]
) t
Where [Share%] >= 50
Order By Customer Desc;
You can't define [Sale] column and use it in a function in the same SQL.
Easiest way to achieve this is just to surround your SQL with an outer SQL statement, where you'll also calculate the total sum and make the division.
(My syntax might not be MS-SQL exact, but this is to illustrate the idea)
Select [data].[FirstName],
format([data].[Sale],'0.00'),
format([data].[Sale] / [total].[totalSum],'0.00') FROM
(Select IsNull([Customer].[FirstName],'Total') as Customer,
Sum([MY_DB].[dbo].[Order].[TotalAmount] [Sale],
From Customer
INNER JOIN [MY_DB].[dbo].[Order]
ON [Customer].[Id]=[MY_DB].[dbo].[Order].[CustomerId]
Group By [Customer].[FirstName] with Rollup
Having (Sum([MY_DB].[dbo].[Order].[TotalAmount]) > (Select AVG([MY_DB].[dbo].[Order].[TotalAmount]) From [MY_DB].[dbo].[Order])) ) data,
(Select sum([MY_DB].[dbo].[Order].[TotalAmount] as [totalSum]) from [MY_DB].[dbo].[Order]) total
Order By [data].[FirstName] Desc;

SQL: Sort Results of a Query Based on the Order of values from another Query

Suppose I have a table with 3 columns:
YEAR
COMPANY
DEPARTMENT
SALES
And I wanted to display the following:
COMPANY
DEPARTMENT
SUM(SALES)
The additional requirement being that the COMPANY with the Maximum Sales (across all departments) shows first, and the rest of the results ordered accordingly.
How would I go about writing my query?
I've tried the following, and it doesn't work:
SELECT t1.company,
cs1.deparment,
SUM(cs1.sales)
FROM company_sales cs1,
(SELECT cs2.company,
SUM(cs2.sales)
FROM company_sales cs2
WHERE cs2.company IS NOT NULL
GROUP BY cs2.company
ORDER BY 2 DESC) t1
WHERE cs1.company = t1.company
GROUP BY t1.company,
cs1.deparment;
You can do this using window functions:
select company, department, sum(sales)
from t
group by company, department
order by sum(sum(sales)) over (partition by company) desc, company;
You can also include the expression in the select clause to see the sum of sales for the entire company.
Try:
SELECT company,department,sum(sales)
FROM table GROUP BY company,department
ORDER BY Max(sales)