Is there a possibility to minimize three CASE-functions into one while I'm expecting three different expressions for any CASE?
So all CASE-calls are dependent on one value (con.category_id).
I hope you can help me to clean up this SQL statement by conserving the whole functionality.
SELECT
UNIX_TIMESTAMP(con.content_date_publishing) AS time,
CASE
when con.category_id IS NOT NULL
THEN
con.category_id
ELSE
0
END AS category_id,
CASE
when con.category_id IS NOT NULL
THEN
cat.category_name_de
ELSE
NULL
END AS category_name
FROM
v5_content AS con,
v5_category AS cat
WHERE content_id = 2 AND
CASE
when con.category_id IS NOT NULL
THEN
con.category_id = cat.category_id
ELSE
1
END
LIMIT
1
Looks like you're missing the LEFT JOIN operator.
SELECT
UNIX_TIMESTAMP(con.content_date_publishing) AS time,
cat.category_id,
cat.category_name_de
FROM v5_content as con
LEFT JOIN v5 category as cat ON con.category_id = cat.category_id
WHERE
content_id = 2;
Related
I have table data like
value pvalue value_type
an1001 bk1001 1
an1002 null 1
an1003 null 1
an1004 bk1002 1
bk1001 ck1001 2
bk1002 ck1002 2
ck1001 MG1001 3
ck1002 null 3
I m expecting result like
value pvalue1 pvalue2 pvalue2
an1001 bk1001 ck1001 MG1001
an1002 bk1002 ck1002
an1003
an1004
is there any way to write queries where i can avoid left outer join or inner join rather that i can use inline queires
You can use something like the following query. Please mind the syntax errors, if any.
select value,
max(case when value_type = 1 then pvalue else null end) as pvalue1,
max(case when value_type = 2 then pvalue else null end) as pvalue2,
max(case when value_type = 3 then pvalue else null end) as pvalue3
from table
group by value;
I want to select a userid from a single table based on multiple and condition.
UserID FieldID Value
-----------------------------------
1 51 Yes
1 6 Dog
2 6 Cat
1 68 TX
1 69 78701
2 68 LA
What I'm trying to get in simple words:
if user search for texas or 78701,
Select userId where (68 = TX OR 69=78701) AND (51=yes) AND (6=Dog)
This should return user id 1.
This is what I tried, but returns null.
SELECT user_id FROM `metadata`
WHERE ( (`field_id` = '68' AND value LIKE '%TX%')
OR (`field_id` = '69' AND value LIKE '%78701%') )
AND `field_id` = '51' AND value = 'Yes'
AND `field_id` = '6' AND value = 'Dog'
You can use GROUP BY with a HAVING clause that makes use of multiple conditional aggregates:
SELECT UserID
FROM metadata
GROUP BY UserID
HAVING SUM(field_id = '68' AND value LIKE '%TX%' OR
field_id = '69' AND value LIKE '%78701%') >= 1
AND
SUM(field_id = '51' AND value = 'Yes') >= 1
AND
SUM(field_id = '6' AND value = 'Dog') >= 1
Demo here
Explanation: In MysQL a boolean expression, like
field_id = '51' AND value = 'Yes'
returns 1 when true, 0 when false.
Also, each predicate of HAVING clause is applied to the whole group of records, as defined by GROUP BY.
Hence, predicate:
SUM(field_id = '51' AND value = 'Yes') >= 1
is like saying: return only those UserID groups having at least one (>=1) record with
field_id = '51' AND value = 'Yes' -> true
Your table structure resembles attribute+value modelling, which essentially splits up the columns of a row into individual pairs, and has the side effect of very weak typing.
As you've noted, this can also make things tricky to query, since you have to reason over multiple rows in order to make sense of the original data model.
One approach could be to take an opinion of a 'primary' criterion, and then apply additional criteria by reasoning over the shredded data, joined back by user id:
SELECT DISTINCT m.user_id
FROM `metadata` m
WHERE ((`field_id` = '68' AND value LIKE '%TX%')
OR (`field_id` = '69' AND value LIKE '%78701%'))
AND EXISTS
(SELECT 1
FROM `metadata` m2
WHERE m2.user_id = m.user_id AND m2.field_id = '51' AND m2.value = 'Yes')
AND EXISTS
(SELECT 1
FROM `metadata` m3
WHERE m3.user_id = m.user_id AND m3.field_id = '6' AND m3.value = 'Dog');
However, IMO, it may be better to attempt to remodel the table like so (and ideally choose better descriptions for the attributes as columns):
UserID Field51 Field6 Field68 Field69
----------------------------------------
1 Yes Dog TX 78701
2 No Cat LA NULL
This will make things much easier to query.
This approach is typically slower than simply LEFT JOINing that table on each criterion, but it can make the problem simpler to comprehend...
SELECT userid
, MAX(CASE WHEN fieldid = 51 THEN value END) smoker
, MAX(CASE WHEN fieldid = 6 THEN value END) favourite_pet
, MAX(CASE WHEN fieldid = 68 THEN value END) state
, MAX(CASE WHEN fieldid = 69 THEN value END) zip
FROM eav
GROUP
BY userid;
You can use HAVING, or bundle this into a subquery to get the desired results.
SELECT user_id FROM metadata
WHERE
(field_id = '68' AND value LIKE '%TX%')
OR (field_id = '69' AND value LIKE '%78701%')
AND (field_id = '51' AND value = 'Yes')
AND (field_id = '6' AND value = 'Dog');
I have little bit changed your query and tried with the same,it gives output as, user_id is 1
While Combining Query is
SELECT
stdt.`DIST_VC_DNE`,
COUNT(Farmer_ID) AS Farmer_Cnt,
SUM(
CASE
WHEN STATUS = 'Analysed' THEN 1
ELSE 0
END
) AS Analysed_Cnt
FROM
`tt_mao_soil_sample_dtls` tms
INNER JOIN tt_mao_soil_farmer_dtls FAR ON FAR.`Soil_Sample_ID` = tms.`Soil_Sample_ID`
INNER JOIN `st_com_dist` STDT ON STDT.DIST_VC_DC = tms.District_ID
WHERE
Far.print_status IS NULL
AND Is_active = 'Y'
AND stl_user_id = 2222
AND Unique_ID LIKE '2016-17%'
GROUP BY
District_ID;
And Resultset Is
DIST_VC_DNE | Farmer_Cnt | Analysed_Cnt
----------------------------------------
AP 24340 20177
TS 4 0
While writing indivudual Query-
SELECT DIST_VC_DNE,COUNT(*) AS Analysed_Cnt
FROM tt_mao_soil_sample_dtls
WHERE `district_id`=10 AND Is_active='Y' AND stl_user_id=2222
AND Unique_ID LIKE '2016-17%';
And Resultset Is
DIST_VC_DNE | Analysed_Cnt
---------------------------
AP 13065 <===This is the correct result
Please check your joins in the first query. This is the reason its returning the wrong count value. When you have no joins in the 2nd query you get the right count value.
I'm not familiar with the data so unable to help further.
I don't know if it is possible, but I thought I could ask
I have a table with families and subfamilies (family_table):
family_id family_name parent_id
1 Family 1 null
2 Family 2 null
3 Subfamily 1.1 1
4 Subfamily 1.2 1
5 Family 3 null
6 Subfamily 2.1 2
Then I have a complicated SELECT that returns some family_id, like 2, 4.
Then I would need to return the following information:
principal_id family_name subfamily_id subfamily_name
2 Family 2 null null
1 Family 1 4 Subfamily 1.2
EDIT: I wouldn't mind changing how the results are shown or changing something else as long as it is clear enough.
Here it's what I've done so far:
SELECT
CASE
WHEN ft.parent_id IS NULL THEN
ft.family_id
ELSE
ft.parent_id
END AS principal_id,
/*I was thinking something like this, but I don't know how to select another row value here, or if there would be another way
CASE
WHEN ft.parent_id IS NULL THEN
ft.family_name
ELSE
*Family name from the parent*
END AS family_name*/
FROM
family_table ft
LEFT JOIN family_table ft2 ON ft2.parent_id = ft.family_id
WHERE
ft.family_id IN (2,4/*complicated select*/)
EDIT: THIS ATTEMPT BELOW WOULDN'T WORK, AS IT RETURNS THE RESULTS FROM A SUBFAMILY AS A FAMILY, and it doesn't join the parent ID from the subfamily, which I need.
Or maybe something like this:
SELECT
ft.family_id as principal_id,
ft.family_name as family_name,
ft2.family_id as subfamily_id,
ft2.family_name as subfamily_name
FROM ft.family_table
LEFT JOIN ft2.family_table ON ft2.parent_id = ft.family_id
WHERE
/*ft.family_id OR ft2.parent_id*/ IN (2,4/*complicated select*/)
I don't want to repeat the monstrous select by doing ft.family_id IN (2,4/*complicated select*/) OR cf2.parent_id IN (2,4/*complicated select*/).
I have the feeling that I am over-complicating everything...
HERE IT IS THE FINAL QUERY, TAKING THE ACCEPTED ANSWER INTO ACCOUNT (in case someone was wondering)
SELECT
COALESCE (ft2.family_id, ft.family_id) AS family_id,
COALESCE (ft2.family_name, ft.family_name) AS family_name,
CASE WHEN ft.parent_id IS NOT NULL THEN ft.family_id
END AS subfamily_id,
CASE WHEN ft.parent_id IS NOT NULL THEN ft.family_name
END AS subfamily_name
FROM family_table ft
JOIN (/* complicated select */) AS t ON t.family_id IN (ft.family_id, ft.parent_id)
LEFT JOIN family_table ft2 ON ft2.family_id = ft.parent_id
Try joining to the "complicated select" instead of using IN() , something like this:
SELECT
.....
FROM
family_table ft
LEFT JOIN family_table ft2 ON ft2.parent_id = ft.family_id
JOIN ( /* complicated select here */ ) t
ON(t.ID_OR_WHATEVER IN(ft.family_id,cf2.parent_id))
This will have the same effect.
The goal
Get the lowest price of a product.
The problem
To illustrate my problem:
Row 1
Product_Id = 1
Product_Name = "iPhone 5"
Market_Name = "Walmart"
Product_Original_Price = "359.00"
Product_Promotional_Price = "319.00"
Product_State = 1 (is on offer)
Row 2
Product_Id = 1
Product_Name = "iPhone 5"
Market_Name = "Apple"
Product_Original_Price = "359.00"
Product_Promotional_Price = "0.00"
Product_State = 0 (isn't on offer)
Row 3
Product_Id = 1
Product_Name = "iPhone 5"
Market_Name = "BestBuy"
Product_Original_Price = "359.00"
Product_Promotional_Price = "299.00"
Product_State = 1 (is on offer)
The query of the next topic (What I have) is returning me zero as the best price of the problem illustrated above — but the best price is 299.00, by BestBuy, because zero at Product_Promotional_Price means that the product isn't on offer.
What I have
SELECT
MIN(LEAST(`Product_Original_Price`, `Product_Promotional_Price`)) as `minProductPrice`
[...]
Details
My query:
SELECT `pr`.`Product_Id` as `productId`,
`pr`.`Product_Name` as `productName`,
ROUND(CAST(MIN(`map`.`Product_Original_Price`) AS DECIMAL)/100,2)
as `minProductPrice`,
`prm`.`Product_Measure_Name` as `measureName`,
`prm`.`Product_Measure_Shortname` as `measureShortName`,
`pri`.`Product_Thumbnail_Image_Url` as `thumbnailUrl`,
`pr`.`Product_Markets_Quantity` as `numberOfMarketsThatHaveThisProduct`
FROM `bm_market_products` as `map`
JOIN `bm_products` as `pr` ON `map`.`Product_Id` = `pr`.`Product_Id`
JOIN `bm_products_category_relationship` as `car` ON `pr`.`Product_Id` =
`car`.`Product_Id`
JOIN `bm_product_categories` as `ca` ON `car`.`Category_Id` = `ca`.`Category_Id`
JOIN `bm_products_measure_relationship` as `prmr` ON `pr`.`Product_Id` =
`prmr`.`Product_Id`
JOIN `bm_product_measures` as `prm` ON `prmr`.`Measure_Id` =
`prm`.`Product_Measure_Id`
JOIN `bm_products_images` as `pri` ON `pr`.`Product_Id` = `pri`.`Product_Id`
WHERE ("" IS NULL OR `map`.`Product_State` = 0)
AND ("" IS NULL OR `ca`.`Category_Id` = 14)
GROUP BY `map`.`Product_Id`;
What the query returns:
What I already have tried:
Considering that Product_State determines whether a product is on offer or not, follow this fragment:
SELECT `pr`.`Product_Id` as `productId`,
`pr`.`Product_Name` as `productName`,
(IF(`map`.`Product_State` <> 0) THEN
MIN(LEAST(`Product_Original_Price`, `Product_Promotional_Price`))
ELSE (`map`.Product_Original_Price) as `minProductPrice`,
`prm`.`Product_Measure_Name` as `measureName`,
`prm`.`Product_Measure_Shortname` as `measureShortName`,
`pri`.`Product_Thumbnail_Image_Url` as `thumbnailUrl`,
`pr`.`Product_Markets_Quantity` as `numberOfMarketsThatHaveThisProduct`
[...]
Can you see the IF/THEN/ELSE? This is what has been added in relation to the previous query.
The above query doesn't work — syntax isn't correct, I know, but it was just to illustrate.
The solution
Gordon Linoff posted this answer and with it, I made this:
SELECT [...]
ROUND(CAST(MIN(CASE WHEN `map`.`Product_Promotional_Price` = 0 THEN `map`.`Product_Original_Price`
ELSE LEAST(`map`.`Product_Promotional_Price`, `map`.`Product_Original_Price`)
end) AS DECIMAL)/100,2) as `minProductPrice`,
[...]
To clarify, I just adapted his [Gordon Linoff] syntax to my scenario — with ROUND to rounding numbers and CAST to set a value as a certain type.
Worked perfectly!! Thanks!!
You need to fix your logic for getting the lowest price. A case statement is the best way. Here is an example:
select MIN(case when `Product_Promotional_Price` = 0 then `Product_Original_Price`
else least(`Product_Promotional_Price`, `Product_Original_Price`)
end)
put where Product_Original_Price!=0 and Product_Promotional_Price!=0 to the end;