How to combine two fields and flag them accordingly - sql

I would like to know how to flag customers who did not purchase some items that are described by two fields (product name and product number). I was able to perform this query for customers that did purchase them, but not the opposite. Thank you in advance for your help!
Here is part of my SQL query.
Select customer_id, product_name, product_number
from table
where
((PRODUCT_NAME = 'LIAM' AND PRODUCT_NUMBER = '212') OR
(PRODUCT_NAME = 'ARRAY' AND PRODUCT_NUMBER = '325')
)
Here is an example:
1 LIAM 212
1 STACY 452
1 NEIL 789
1 LIAM 345
2 ROSE 234
2 LIAM 345
2 ARRAY 325
3 STACY 452
3 ARRAY 625
Query Result:
1 ARRAY 325
2 LIAM 212
3 ARRAY 325
3 LIAM 212

You seems want not exists :
select t.*
from table t
where not exists (select 1
from table t1
where t1.customer_id = t.customer_id and
t1.PRODUCT_NAME in ('LIAM', 'ARRAY')
);
I don't see any advantage using of both Product_name and Product_number in the where clause if they are defined unique in table.
By this way, you will get customer's who never purchased liam or array product.

Related

MS Access SQL, How to return only the newest row before a given date joined to a master table

I have two tables in a MS Access database as shown below. CustomerId is a primary key and fkCustomerId is a foreign key linked to the CustomerId in the other table.
Customer table
CustomerId
Name
1
John
2
Bob
3
David
Purchase table
fkCustomerId
OrderDate
fkStockId
1
01/02/2010
100
3
08/07/2010
101
2
14/01/2011
102
2
21/10/2011
103
3
02/03/2012
104
1
30/09/2012
105
3
01/01/2013
106
1
18/04/2014
107
3
22/11/2015
108
I am trying to return a list of customers showing the last fkStockId for each customer ordered before a given date.
So for the date 01/10/2012, I'd be looking for a return of
fkCustomerId
Name
fkStockId
1
John
105
2
Bob
103
3
David
104
A solution seems to be escaping me, any help would be greatly appreciated.
You can use nested select to get last order date.
SELECT Purchase.fkCustomerId,
Name,
fkStockId
FROM Purchase
JOIN
(
SELECT fkCustomerId,
MAX(OrderDate) as last_OrderDate
FROM Purchase
WHERE OrderDate < '01/10/2012'
GROUP BY fkCustomerId
) AS lastOrder
ON lastOrder.fkCustomerId = Purchase.fkCustomerId
AND last_OrderDate = OrderDate
LEFT JOIN Customer
ON Customer.CustomerId = Purchase.fkCustomerId
This example assumes OrderDate before '01/10/2012'. You might need to change it if you want it to be filtered by a different value.
Another assumption is that there's only one corresponding fkStockId for each OrderDate

Combine multiple records into one based on a condition

I want to combine each product_code's (comma-separated) in a single entry/record if all other values in multiple records are the same except the product_code
The dataset looks like below-
category_id subcat_id product_code customer_id quantity value
123 456 AB 111 2 1
123 456 CD 111 2 1
123 789 AB 111 2 2
123 789 CD 111 2 2
The result should look like-
category_id subcat_id product_code customer_id quantity value
123 456 AB,CD 111 2 1
123 789 AB,CD 111 2 2
Use string_agg();
select category_id, subcat_id, customer_id, quantity, value,
string_agg(product_code, ',')
from t
group by category_id, subcat_id, customer_id, quantity, value;
That said, I recommend arrays instead of strings for storing such values.

Postgres: Convert single rows from multiple tables into multiple rows in a single table

I have data scattered across multiple tables and rows that I'd like to aggregate into a more usable format for my use case. The problem boils down to something like this...
If I have two tables like this:
product_id title_id description_id
1 123 234
2 345 456
3 567 678
product_id additional_info_id
1 789
1 890
2 901
How would I construct a query to return data like this?
product_id content_id content_type
1 123 title
1 234 description
1 789 additional_info
1 890 additional_info
2 345 title
2 456 description
2 901 additional_info
3 567 title
3 678 Description
I found this post and I can construct a query like this
select
p.product_id,
p_content.*
from
product p,
lateral (values
(p.title_id, 'title'),
(p.description_id, 'description')
) p_content (content_id, content_type)
;
to get the data from the product table in the format I need, but I can't figure out how to incorporate the data from the additional_info table.
You can use union all:
select p.product_id, v.content_id, v.content_type
from product p cross join lateral
(values (p.title_id, 'title'),
(p.description_id, 'description')
) v(content_id, content_type)
union all
select product_id, additional_info_id, 'additional_info'
from additional_info ai;

Select objects with child objects that have both null and non-null attributes

Say I have a table that links a parent object with multiple child objects and has columns for certain attributes of the child object. Take this simplified example below:
product_id sku_id size_desc color_column_that_doesnt_matter
123 456 (null) black
123 457 (null) red
123 458 (null) grey
124 567 large green
124 568 medium green
124 569 small green
125 678 (null) blue
125 679 5x5 yellow
Notice that Product 123 and 124 have products that all have either a null for the size description or a value for the size description. Product 125 is different though - It has at least one sku w/ a null size_desc and at least one one sku that has a non-null value for size_desc.
Say there are potentially very many products like Product 125 - I want them all. How would I filter this data via a select…where statement to return all products and all skus that have this mix of null and non-null values for size_desc?
SQL flavor is Oracle 11
You can get the products like this:
select product_id
from table t
group by product_id
having count(*) <> count(size_desc) and count(size_desc) > 0;
You can get the detail for all these products by switching this to analytic functions:
select t.*
from (select t.*, count(*) over (partition by product) as cnt,
count(size_desc) over (partition by product) as cnt_sizedesc
from t
) t
where cnt <> cnt_sizedesc and cnt_sizedesc > 0;

SQL: How do I count the number of clients that have already bought the same product?

I have a table like the one below. It is a record of daily featured products and the customers that purchased them (similar to a daily deal site). A given client can only purchase a product one time per feature, but they may purchase the same product if it is featured multiple times.
FeatureID | ClientID | FeatureDate | ProductID
1 1002 2011-05-01 500
1 2333 2011-05-01 500
1 4458 2011-05-01 500
2 8888 2011-05-10 700
2 2333 2011-05-10 700
2 1111 2011-05-10 700
3 1002 2011-05-20 500
3 4444 2011-05-20 500
4 4444 2011-05-30 500
4 2333 2011-05-30 500
4 1002 2011-05-30 500
I want to count by FeatureID the number of clients that purchased FeatureID X AND who purchased the same productID during a previous feature.
For the table above the expected result would be:
FeatureID | CountofReturningClients
1 0
2 0
3 1
4 3
Ideally I would like to do this with SQL, but am also open to doing some manipulation in Excel/PowerPivot. Thanks!!
If you join your table to itself, you can find the data you're looking for. Be careful, because this query can take a long time if the table has a lot of data and is not indexed well.
SELECT t_current.FEATUREID, COUNT(DISTINCT t_prior.CLIENTID)
FROM table_name t_current
LEFT JOIN table_name t_prior
ON t_current.FEATUREDATE > t_prior.FEATUREDATE
AND t_current.CLIENTID = t_prior.CLIENTID
AND t_current.PRODUCTID = t_prior.PRODUCTID
GROUP BY t_current.FEATUREID
"Per feature, count the clients who match for any earlier Features with the same product"
SELECT
Curr.FeatureID
COUNT(DISTINCT Prev.ClientID) AS CountofReturningClients --edit thanks to feedback
FROM
MyTable Curr
LEFT JOIN
MyTable Prev WHERE Curr.FeatureID > Prev.FeatureID
AND Curr.ClientID = Prev.ClientID
AND Curr.ProductID = Prev.ProductID
GROUP BY
Curr.FeatureID
Assumptions: You have a table called Features that is:
FeatureID, FeatureDate, ProductID
If not then you could always create one on the fly with a temporary table, cte or view.
Then:
SELECT
FeatureID
, (
SELECT COUNT(DISTINCT ClientID) FROM Purchases WHERE Purchases.FeatureDate < Feature.FeatureDate AND Feature.ProductID = Purchases.ProductID
) as CountOfReturningClients
FROM Features
ORDER BY FeatureID
New to this, but wouldn't the following work?
SELECT FeatureID, (CASE WHEN COUNT(clientid) > 1 THEN COUNT(clientid) ELSE 0 END)
FROM table
GROUP BY featureID