query to avoid left outer join or inner join - mysql

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;

Related

MySQL Select User id based on multiple AND conditions on same table

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

How to combine based on id in mysql

Please help to find out the result.How to a write a query to combine rows which has same id
id size sizeorder color colororder
1 M 1 null null
1 null null red 1
2 s 1 null null
2 Null null green 2
output should be
id size sizeorder color colororder
1 M 1 red 1
2 s 1 green 2
SELECT id,
MAX(size) AS size,
MAX(sizeorder) AS sizeorder,
MAX(color) AS color,
MAX(colororder) AS colororder
FROM yourTable
GROUP BY id
The rollup you are trying to do is similar to what happens in a pivot query. The "secret sauce" in the above query is that MySQL's MAX function ignores NULL values. This means that in your table only the non NULL values will be retained in each column, for each grouped id.
You have to join your tables and use case when to get the value which is not null:
select case when t1.size is null then t2.size else t1.size end as size,
case when t1.sizeorder is null then t2.sizeorder else t1.sizeorder end as sizeorder,
case when t1.color is null then t2.color else t1.color end as color
case when t1.colororder is null then t2.colororder else t1.colororder end as colororder
from <table> t1 join <table> t2 on t1.id = t2.id

SQL query to set a value if data exist

Here's the fiddle;
http://sqlfiddle.com/#!2/af8015/9
I've some data, and I want to set
if user and g parameter are in table named cl, result column should
be 1;
if user and g parameter are in table named im, but not in cl, result
column should be -1;
else, result column should be 0
I'm using following query;
select *,
case cl.user_id
when null then -1
when im.user_id then 1
end as result
from im
left join cl on cl.user_id = im.user_id
and cl.id_g = im.id_g
left join user on user.user_id = im.user_id
left join g on g.id_g = im.id_g
But, it returns null for -1, and I couldn't set 0 for the last case.
Expected result table is;
user id - g id - result
1 1 1
1 2 1
1 3 0
1 4 1
2 1 1
2 2 1
2 3 -1
2 4 0
...
I can't see a way of generating the 0 result from your sample data.
I believe your result parameter should be computed like this;
IF (cl.user_id IS NOT NULL and cl.id_g IS NOT NULL, 1,
IF(im.user_id IS NOT NULL and im.id_g IS NOT NULL, -1,0)
) result
And, I think your series of JOIN operations should go like this.
FROM user
LEFT JOIN im ON user.user_id = im.user_id
LEFT JOIN cl ON user.user_id = cl.user_id AND im.id_g = cl.id_g
LEFT JOIN g ON im.id_g = g.id_g
That is, you should lead with the user table. Here's an example: http://sqlfiddle.com/#!2/a5c6ef/1/0
Your result parameter is computed like this:
case cl.user_id
when null then -1
when im.user_id then 1
end as result
null values work strangely. A null value can never compare equal to anything, even another null value, so when null then -1 will never fire. This expression, on the other hand, should work.
case when cl.user_id IS NULL then -1
when im.user_id IS NULL then 1
else 0 end as result

MySQL sum up some CASE WHEN functions

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;

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.