SQL Count of two values in one column - sql

I have a table with customer name and Status columns. The status column has two values
Test
Live
The customers appear more than once and can be classed as either test, live or BOTH like below:
**Customer | Status**
Logistics | Test
Logistics | Live
Ample | Live
What I want is a query to give me a count of the number of distinct customers who fall under both statuses. So using the above table, I would count customer logistics (since it has both test and live) but not ample (since it is just live).
Any ideas?

You can use group by clause :
select Customer, count(*)
from table t
group by Customer
having min(status) <> max(status);
If you want it with specific status then include where clause :
select Customer, count(*)
from table t
where status in ('Test', 'Live')
group by Customer
having count(distinct status) = 2;
EDIT : If you want other columns too, then i would prefer :
select t.*
from table t
where exists (select 1 from table t1 where t1.Customer = t.Customer and t1.status <> t.status);

try something like this:
select customer
from
(select customer, max(IsTest) as IsTest , max(IsLive) as IsLive
from
(select customer,
case when status='test' then 1 else 0 end as IsTest,
case when status='live' then 1 else 0 end as IsLive
from table) a
group by customer) b
where IsTest = 1 and IsLive = 1

you can use group by clause to get your desire output.
select Customer, count(*)
from table t
group by Customer
having min(status) <> max(status);

Related

T-SQL query to find the required output

I am new to SQL queries, I have some data and I am trying to find the result which is shown below.
In my sample data, I have customer ID repeating multiple times due to multiple locations, What I am looking to do is create a query which gives output shown in image output format,
If customer exists only once I take that row
If customer exists more than once, I check the country; if Country = 'US', I take that ROW and discard others
If customer exists more than once and country is not US, then I pick the first row
PLEASE NOTE: I Have 35 columns and I dont want to change the ROWS order as I have to select the 1st row in case customer exist more than once and country is not 'US'.
What I have tried: I am trying to do this using rank function but was unsuccessful. Not sure if my approach is right, Please anyone share the T-SQL query for the problem.
Regards,
Rahul
Sample data:
Output required :
I have created a (short) dbfiddle
Short explanation (to just repeat the code here on SO):
Step1:
-- select everyting, and 'US' as first row
SELECT
cust_id,
country,
sales,
CASE WHEN country='US' THEN 0 ELSE 1 END X,
ROW_NUMBER() OVER (PARTITION BY cust_id
ORDER BY (CASE WHEN country='US' THEN 0 ELSE 1 END)) R
FROM table1
ORDER BY cust_id, CASE WHEN country='US' THEN 0 ELSE 1 END;
Step2:
-- filter only rows which are first row...
SELECT *
FROM (
SELECT
cust_id,
country,
sales,
CASE WHEN country='US' THEN 0 ELSE 1 END X,
ROW_NUMBER() OVER (PARTITION BY cust_id
ORDER BY (CASE WHEN country='US' THEN 0 ELSE 1 END)) R
FROM table1
-- ORDER BY cust_id, CASE WHEN country='US' THEN 0 ELSE 1 END
) x
WHERE x.R=1
I can't vouch for performance but it should work on SQL Server 2005. Assuming your table is named CustomerData try this:
select cust_id, country, Name, Sales, [Group]
from CustomerData
where country = 'US'
union
select c.* from CustomerData c
join (
select cust_id, min(country) country
from CustomerData
where cust_id not in (
select cust_id
from CustomerData
where country = 'US'
)
group by cust_id
) a on a.cust_id = c.cust_id and a.country = c.country
It works by finding all those with a record with US as the country and then unioning that with the first country from every record that doesn't have the US as a country. If min() isn't getting the country you want then you'll need to find an alternative aggregation function that will select the country you want.

Count on Table 1 based on Count with Clause on Table 2, sql

Table 1
Table 2
I need to find the Count of total number of unique stores that have "Achieved Date" not Null that achieved all of the "Achievement Ids" "enabled" on Table 2.
So far I can find the count of stores that achieved a hard coded number, but I'm not breaking through the part where I use the Count of Enabled Ids on table 2 to define what the number is.
SELECT
COUNT(*) AS count
FROM
(SELECT
StoreNumber, COUNT(*) as Achievements
FROM
StoreAchievementProgress
WHERE
AchievedDate IS NOT NULL
GROUP BY
StoreNumber) count
maybe this query
SELECT S.StoreNumber
FROM StoreAchievementProgress S
RIGHT JOIN (SELECT Id FROM Table2 WHERE Enabled=1 )T
ON T.Id=S.AchievementId
AND AchievedDate IS NOT NULL
GROUP BY S.StoreNumber
HAVING COUNT(1) = (SELECT COUNT(Id) FROM Table2 WHERE Enabled=1 )
Joining the stores with a count of their enabled achievements to how many they can get
SELECT COUNT(*) AS StoresFullAchievements
FROM
(
SELECT p.StoreNumber, COUNT(*) AS TotalEnabledAchievements
FROM StoreAchievementProgress p
JOIN Achievements a ON a.id = p.AchievementId
WHERE p.AchievedDate IS NOT NULL
AND a.Enabled = 1
GROUP BY p.StoreNumber
) AS s
JOIN
(
SELECT COUNT(*) AS TotalEnabled
FROM Achievements
WHERE Enabled = 1
) a
ON a.TotalEnabled = s.TotalEnabledAchievements

SQL set column with derived value

How to I set a column value to "1" where sum(price) >= 88
Eg: if sum(price) for customer A is more than or equal than 88, delivery will be updated as "Y"
customer table: name, price, delivery (i only listed out the important column)
My SQL query:
UPDATE customer
SET delivery ='Y'
WHERE (SELECT SUM(price) FROM customer
GROUP BY name )>=88;
Error: You can't specify target table "customer" for update in FROM clause
See attached table:
You don't have any join between the table you're updating and your subselect. Your table doesn't really have a key, but given what you've shown I'd do it like:
update Orders
set delivery = 'Y'
where Name in (SELECT NAME FROM
(SELECT NAME, SUM(PRICE) TOTAL_PRICE
FROM ORDERS
GROUP BY NAME
HAVING SUM(PRICE)> 88) A
)
So basically it gets the Name of each customer and the sum or their order prices but only where the sum is over 88. It then just pulls out the Name from that subselect and only updates the rows where the name exists in the list of names for orders that sum over 88.
Set the column to the value that you selecting from the table and don't group them.
SET COLUMN_X = (SELECT SUM(price) FROM customer)
Now you use your query and it looks cleaner
UPDATE customer
SET delivery ='Y'
WHERE COLUMN_X = >=88;
You don't say which database you are using (or which version of it), so you may try if this standard SQL works on it:
with
x as (
select name
from customer
group by name
having sum(price) > 88
)
update customer c
set delivery = 'Y'
where name in (select name from x)
Essentially the same thing #TheImpaler just posted, but with a subquery instead of a CTE.
Get the names that qualify first, then join to that list for the UPDATE statement.
UPDATE t
SET delivery = 'Y'
FROM
#t AS t
JOIN
(
SELECT
name
,SUM(price) AS total
FROM
#t
GROUP BY
name
HAVING
SUM(price) >= 88
) AS d
ON
d.name = t.name;
Here's a working Rextester: https://rextester.com/LQWE88535

SQL querying a customer ID who ordered both product A and B

Having a bit of trouble when trying to figure out how to return a query of a customer who ordered both A and B
What I'm looking for is all customers who order both product A and product B
SELECT CustomerID
FROM table
WHERE product in ('a','b')
GROUP BY customerid
HAVING COUNT(distinct product) = 2
I don't normally post code only answers but there isn't a lot that words can add to this- the query predominantly explains itself
You can also
HAVING max(product) <> min(product)
It may be worth pointing out that in queries, the WHERE is performed, filtering to just products A and B. Then the GROUP BY is performed, grouping customer and counting the distinct number of products (or getting the min and max). Then the HAVING is performed, filtering to just those with 2 distinct products (or getting only those where MIN i.e. A, is different to MAX i.e. B)
If you'v never encountered HAVING, it is logically equivalent to:
SELECT CustomerID
FROM(
SELECT CustomerID, COUNT(distinct product) as count_distinct_product
FROM table
WHERE product in ('a','b')
GROUP BY customerid
)z
WHERE
z.count_distinct_product = 2
In a HAVING clause you can only refer to columns that are mentioned in the group by. You can also refer to aggregate operations (such as count/min/max) on other columns not mentioned in the group by
I have never worked with SQLLite, but since it's specs say it is a Relational Database, it should allow the following query.
select CustomerID
from table t
where exists (
select *
from table
where CustomerID = t.CustomerID
and Product = 'A'
)
and exists (
select *
from table
where CustomerID = t.CustomerID
and Product = 'B'
)
I'd use a correlated sub-query with a HAVING clause to scoop in both products in a single WHERE clause.
SELECT
t.Customer
FROM
#t AS t
WHERE
EXISTS
(
SELECT
1
FROM
#t AS s
WHERE
t.Customer = s.Customer
AND s.Product IN ('A', 'B')
HAVING
COUNT(DISTINCT s.Product) = 2
)
GROUP BY
t.Customer;
Select customerid from table group by customerid having product like 'A' and product like 'B' or
you can try having count(distinct product) =2this seems to be more accurate.
The whole idea is in a group of customerid suppose 1 if I have several A's and B's count(distinct product) will give as 2 else it will be 1 so the answer is as above.
Another way I just figured out was
SELECT CustomerID
FROM table
WHERE product in ('a','b')
GROUP BY customerid
HAVING sum(case product ='a' then 1 else 0 end) > 0
and sum(case when product ='b' then 1 else 0 end) > 0

Select one value if two are present

I have a table with, let's say, 3 columns: Store, Product, Status
Table, in some cases, returns 2 rows for one store and product but with different status:
Store Product Status
120 255 SYSTEM
120 255 USER
What I want to do is to get a row with USER if both are present (USER and SYSTEM), but if only one Status is present, I want to get a present one.
Any ideas?
One way is to use grouping and the max aggregate function:
select store, product, max(status) as status
from t
group by store, product;
This will get you the only present row if there's only one, or if there is both USER and SYSTEM present in the group you will get the USER row(s) (as USER is sorted after SYSTEM).
SELECT Store, Product, Status
FROM TABLE T1
WHERE 1 = (SELECT COUNT(*) FROM TABLE T2
WHERE T1.STORE = T2.STORE AND T1.PRODUCT= T2.PRODUCT)
UNION
SELECT Store, Product, Status
FROM TABLE T1
WHERE 1 < (SELECT COUNT(*) FROM TABLE T2
WHERE T1.STORE = T2.STORE AND T1.PRODUCT= T2.PRODUCT)
AND STATUS = 'USER'
This will work
SELECT TOP 1
Store ,
Product,
Status,
FROM
YourTable
ORDER BY CASE WHEN Status = 'USER' THEN 0 ELSE 1 END