MySQL Select find similar item that has stock - mysql

I have this resultset of my table of products, while trying to return correct results in the last two columns, similar_sku_exists and similar_sku_in_stock.
The goal is, to first determine whether a similar sku exists in the table and return yes/no.
second to determine if either one of the similar skus have stock and return that sku name/s.
A similar sku is defined by the same sku name + first letter of grade.
Eg, all instances of "ABC-11-A" will be similar as they bear the same condition of new. Likewise "ABC-11-B" will be similar in that they are all refurb condition.
id sku condition grade stock similar_sku_exists similar_sku_in_stock
1 ABC-11-A1 new A1 0 yes ABC-11-A2
2 ABC-11-A2 new A2 10 yes
3 ABC-11-B1 refurb B1 10 yes
4 ABC-11-B2 refurb B2 0 yes ABC-11-B1|ABC-11-B2-LP
5 ABC-11-B2-LP refurb B2-LP 10 yes
6 DEF-2-F-A1 new A1 0 no
7 DEF-2-G-B1 refurb B1 10 yes
8 DEF-2-G-B2 refurb B2 0 yes DEF-2-G-B1
So far i have this query but that dosn'nt seem to return correct results
select
id,
sku,
`condition`,
grade,
stock,
case when left(p.sku, length(p.sku)-length(p.grade)+1)
in (select left(p.sku, length(p.sku)-length(p.grade)+1))
then 'yes' else 'no' end as similar_sku_exists,
if(p.stock = 0,
case when left(p.sku, length(p.sku)-length(p.grade)+1)
in (select left(p.sku, length(p.sku)-length(p.grade)+1) and p.stock >0
)
then group_concat(distinct(p.sku) separator '|')
else '' end,'') as similar_sku_in_stock
from products as p
Much appreciated any tought

Here is a method to get the similar skus in stock:
select p.*,
(select group_concat(p2.sku)
from products p2
where substring_index(p2.sku, '-', 1) = substring_index(p.sku, '-', 1) and
left(subsctring_index(p2.sku, '-', -1), 1) = left(substring_index(p.sku, '-', -1), 1) and
p2.sku <> p.sku and
stock > 0
) similar_skus_in_stock
from products p;
A similar query can be used to determine if similar skus exist.

Related

How to select data in mysql that all the joined table is not null on certain column

i have 2 table which is one to many
table order
order_id
order_date
1
2021/01/01
2
2021/01/02
3
2021/01/02
table detail order
detail_order_id
order_id
is_finished
1
1
null
2
1
2021/01/03
3
2
2021/01/04
4
2
2021/01/04
5
3
2021/01/05
6
3
2021/01/06
7
3
null
so i wanna data that have condition if some of the detail order rows is_finished column not null, so the status is gonna be not finish.
and if all the detail order rows is_finished column not contain any null value like id 2, so the status is finished
expected result
order_id
status
1
not finish
2
finished
3
not finish
It seems like you don't really need a join since table_detail_order already have order_id and you only want to check is_finished, you might just need a query on 1 table like:
SELECT order_id,
CASE WHEN SUM(is_finished IS NULL)=0
THEN 'Finished' ELSE 'Not finish' END AS 'Status'
FROM table_detail_order GROUP BY order_id;
Demo fiddle
Btw, is_finished IS NULL will return 1 (true) or 0 (false) so in a table it would look like:
order_id
is_finished
is_finished IS NULL
1
null
1
1
2021/01/03
0
2
2021/01/04
0
2
2021/01/04
0
3
2021/01/05
0
3
2021/01/06
0
3
null
1
Therefore SUM(is_finished IS NULL) with GROUP BY order_id; will do something like this:
order_id
SUM(is_finished IS NULL)
1
1+0=1
2
0+0=0
3
0+0+1=1
And that is why CASE WHEN SUM(is_finished IS NULL)=0 ... is considered as finished while otherwise as not finish.
we can solve the problem like this
left join order and order_detail,but has condition order_details.is_finished is null
so we get a result that the joined order_details's is_finished only null
in that case there is no order_details join with order 2
then we regard the result as a temp table,so when joined order_details has data then it is not finished
here is the example data,you can run query in it
select id,
case when order_id>0 then 'not finish' else 'finished' end as status
from (
select o.id,od.order_id from `order` as o
left join order_detail as od
on (o.id=od.order_id and od.is_finished is null)
group by o.id
) as _t
You can try this. This query uses a LEFT JOIN and COUNT. Where the first count counted the NULL values as ZERO and the second count counts all values, then compare the 2 counts, if the first and second count is equal to each other it means that the order details is finished, if not then not finish.
SELECT a.`order_id`,
IF(COUNT(IF(ISNULL(is_finished),0,1))=COUNT(is_finished), 'finished', 'not finish') AS `status` FROM `order` a
LEFT JOIN `detail_order` b ON a.`order_id`=b.`order_id`
GROUP BY a.`order_id` ;
RESULT*
order_id status
-------- ------------
1 not finish
2 finished
3 not finish

Stuck creating a 0/1 flag that works correctly. Finally giving in

Evening all.
I am trying to create a very basic case statement which buckets three scenarios with a 0 or a 1 in mySQL.
I have three fields found in the reference table link below.
Essentially I am trying to bucket any ProductID that has a StatusCD of 'I' and 'O' as 1, only 'I' as 1 and then anything with only an 'O' result and no corresponding 'I' as a 0. What this data is showing is a product coming into the warehouse ('I') and then exiting the warehouse ('O'). I have other fields which are capturing date differences but ultimately I am trying to create a flag to ignore scenarios where we only have Product#'s with an 'O' statusCD which would indicate their arrival to the warehouse was not logged appropriately and would skew our "Age in warehouse" buckets.
Any insight is greatly appreciated!
Reference Table with fields:
Date | ProductID | StatusCD
2021-01-01 | U1000 | I
2021-01-10 | U1000 | O
2021-01-10 | U2000 | I
2021-01-15 | U3000 | O
Assuming you want to retain every original record, you could use analytic functions here:
SELECT Date, ProductID, StatusCD,
CASE WHEN SUM(StatusCD <> 'O') OVER (PARTITION BY ProductID) = 0
THEN 0 ELSE 1 END As Label
FROM yourTable
ORDER BY Date;
Demo
For versions of MySQL earlier than 8+:
SELECT t1.Date, t1.ProductID, t1.StatusCD,
CASE WHEN t2.OpenCount = 0 THEN 0 ELSE 1 END AS Label
FROM yourTable t1
INNER JOIN
(
SELECT ProductID, SUM(StatusCD <> 'O') AS OpenCount
FROM yourTable
GROUP BY ProductID
) t2
ON t2.ProductID = t1.ProductID
ORDER BY
t1.Date;
Demo

Conditional condition in ON clause

I am trying to apply a conditional condition inside ON clause of a LEFT JOIN. What I am trying to achieve is somewhat like this:
Pseudo Code
SELECT * FROM item AS i
LEFT JOIN sales AS s ON i.sku = s.item_no
AND (some condition)
AND (
IF (s.type = 0 AND s.code = 'me')
ELSEIF (s.type = 1 AND s.code = 'my-group')
ELSEIF (s.type = 2)
)
I want the query to return the row, if it matches any one of the conditions (Edit: and if it matches one, should omit the rest for the same item).
Sample Data
Sales
item_no | type | code | price
1 0 me 10
1 1 my-group 12
1 2 14
2 1 my-group 20
2 2 22
3 2 30
4 0 not-me 40
I want the query to return
item_no | type | code | price
1 0 me 10
2 1 my-group 20
3 2 30
Edit: The sales is table is used to apply special prices for individual users, user groups, and/or all users.
if type = 0, code contains username. (for a single user)
if type = 1, code contains user-group. (for users in a group)
if type = 2, code contains empty-string (for all users).
Use the following SQL (assumed, the the table sales has a unique id field as usual in yii):
SELECT * FROM item AS i
LEFT JOIN sales AS s ON i.sku = s.item_no
AND id = (
SELECT id FROM sales
WHERE item_no = i.sku
AND (type = 0 AND code = 'me' OR
type = 1 AND code = 'my-group' OR
type = 2)
ORDER BY type
LIMIT 1
)
Try following -
SELECT *,SUBSTRING_INDEX(GROUP_CONCAT(s.type ORDER BY s.type),','1) AS `type`, SUBSTRING_INDEX(GROUP_CONCAT(s.code ORDER BY s.type),','1) AS `code`,SUBSTRING_INDEX(GROUP_CONCAT(s.price ORDER BY s.type),','1) AS `price`
FROM item AS i
LEFT JOIN sales AS s
ON i.sku = s.item_no AND (SOME CONDITION)
GROUP BY i.sku

mysql conditional field update

I have 3 columns in CATEGORY TABLE for storing pre-calculated counts of records for it in another table PRODUCTS.
CATEGORY(c_id,name,c30,c31,c32)
c30=count for New Products (value 30)
c31 count for used products (value 31)
c32 count for Damaged products (value 32)
PRODUCT(p_id,c_id,name,condition)
condition can be 30,31 or 32.
I am thinking to write a single UPDATE statement so, it will update respective category count.
Althogh below statement is syntactically wrong, but i am looking for similar type of solution.
select case product.condition
when 30 then update category set category.c30=category.c30+1 where category.c_id=product.category3
when 31 then update category set category.c31=category.c31+1 where category.c_id=product.category3
when 32 then update category set category.c32=category.c32+1 where category.c_id=product.category3
end case
from product
where product.c_id=12
Any suggestion!
You can do this:
UPDATE CATEGORY c
INNER JOIN
(
SELECT
c_id,
SUM(CASE WHEN `condition` = 30 THEN 1 ELSE 0 END) c30,
SUM(CASE WHEN `condition` = 31 THEN 1 ELSE 0 END) c31,
SUM(CASE WHEN `condition` = 32 THEN 1 ELSE 0 END) c32
FROM product
GROUP BY c_id
) p ON c.c_id = p.c_id
SET c.c30 = p.c30,
c.c31 = p.c31,
c.c32 = p.c32;
SQL Fiddle Demo
You can join both the tables and then update the value in same join query.

How do I fetch count of two columns for a given criteria grouped by another column?

DataBase: SQL Fiddle
Query needed: To return the number of women and men of age 25-35 years for each Insurance Company.
My Progress:
CREATE VIEW MenInAge AS
SELECT p.pname,p.pid,p.cid
FROM Patient p
WHERE p.gender = 'm' and p.age between 25 and 35;
CREATE VIEW WomenInAge AS
SELECT p.pname,p.pid,p.cid
FROM Patient p
WHERE p.gender = 'f' and p.age between 25 and 35;
CREATE VIEW MenInAgeCount AS
SELECT m.cid, COUNT(m.pid) as c
FROM MenInAge m
GROUP BY m.cid;
CREATE VIEW WomenInAgeCount AS
SELECT w.cid, COUNT(w.pid) as c
FROM WomenInAge w
GROUP BY w.cid;
How do I show for every InsuranceCompany.cid the WomenInAgeCount.c and the MenInAgeCount.c columns?
Explanation:
You have to join the tables InsuranceCompanies and Patient using the LEFT OUTER JOIN by joining the records on cid column in both tables and also apply the filter to select only patients between age 25 and 35 (including those boundary values). The CASE statement simply checks whether the patient is male or female and computes two different columns by assigning values of 1 if the values match and 0 if the values don't match. Finally you have to group the result by cname to fetch the count by insurance company name.
Explanation about CASE:
In the CASE expression, the query states WHEN gender field value is f assign the column female with the value 1. The value 1 is hard coded because it means the query found 1 row matching the gender='f' record and this also represent 1 person. You can also state ELSE 0 but it is implicit so not necessary to specify that. This CASE expression evaluates for every record in the query result. Finanlly, you will get all the rows with female column containing either 1 or 0. When you sum this column female, you will get the total number of females, the same logic goes for male column.
With COALESCE:
COALESCE here replaces any NULL values with the given value in the second parameter (here in this case zero).
Click here to view the demo in SQL Fiddle.
Script:
SELECT ic.cname
, COALESCE(SUM(CASE WHEN gender = 'f' THEN 1 END), 0) female
, COALESCE(SUM(CASE WHEN gender = 'm' THEN 1 END), 0) male
FROM InsuranceCompanies ic
LEFT OUTER JOIN Patient p
ON p.cid = ic.cid
AND age BETWEEN 25 AND 35
GROUP BY ic.cname;
Output:
CNAME FEMALE MALE
---------- ------ ----
Clalit Inc 0 2
Harel Inc 2 0
Without COALESCE:
Click here to view the demo in SQL Fiddle
Script:
SELECT ic.cname
, SUM(CASE WHEN gender = 'f' THEN 1 END) female
, SUM(CASE WHEN gender = 'm' THEN 1 END) male
FROM InsuranceCompanies ic
LEFT OUTER JOIN Patient p
ON p.cid = ic.cid
AND age BETWEEN 25 AND 35
GROUP BY ic.cname;
Output:
CNAME FEMALE MALE
---------- ------ ----
Clalit Inc NULL 2
Harel Inc 2 NULL
How about a JOIN?
SELECT I.cname, ISNULL(W.c,0) AS WomenCount, ISNULL(M.c,0) as MenCount
FROM InsuranceCompanies AS I
LEFT JOIN MenInAgeCount AS M ON M.cid = I.cid
LEFT JOIN WomenInAgeCount AS W ON W.cid = I.cid
LEFT JOIN here in case the Men or Women view don't contain an entry for each row in the InsuranceCompanies table. The ISNULL is for SQL Server, but you can modify for MySQL, Oracle as needed.
this should give you some help -
select count(pid) as numPatients, cid, gender
from patient
group by cid, gender