Create INTERSECT query in MySQL - mysql

I have a tables
ppv (product_id | property_id | value_id)
and
v (id | property_id | value)
I try to make query to get products where:
select product_id from v, ppv as t INNER JOIN ppv as t2
ON t.product_id = t2.product_id and t1.property_id = t2.property_id
where
( t1.property_id = 1 and v.value > $a and v.value < $b )
and
( t2.property_id = 2 and v.value > $c and v.value < $d )
But havn`t any results. Please help.
So,
ppv (product_id | property_id | value_id)
1 1 50
1 2 2
1 3 3
2 1 28
2 2 2
2 3 29
Next table
v( id | property_id | value)
2 2 3
3 3 2
28 1 2600000
29 3 3
50 1 2500000
** I found a solution to this problem in this way **
SELECT `product_id`,
CONVERT(GROUP_CONCAT(v.`property_id`) USING cp1251) as properties
FROM `values` as v INNER JOIN `product_property_values` as ppv
ON ppv.value_id = v.id
WHERE
(v.`property_id` = 1 and v.value >= 2500000 and v.value <= 3000000 )
or
(v.`property_id` = 2 and v.value >= 1 and v.value <= 3 )
GROUP by product_id
HAVING LOCATE('1', properties) and LOCATE('2', properties)
Th result:
test 1
v.`property_id` = 1 and v.value >= 2500000 and v.value < 3000000
v.`property_id` = 2 and v.value >= 1 and v.value <= 2
product_id properties
Empty
test2
v.`property_id` = 1 and v.value >= 2550000 and v.value < 3000000
v.`property_id` = 2 and v.value >= 1 and v.value <= 4
product_id properties
2 2,1
test3
v.`property_id` = 1 and v.value >= 2000000 and v.value < 3000000
v.`property_id` = 2 and v.value >= 1 and v.value <= 4
product_id properties
1 1,2
2 2,1
It's OK!

It doesn't look like you are actually joining table v. Also, I don't believe it is necessary to link to ppv twice. Try:
SELECT ppv.product_id
FROM v
INNER JOIN ppv ON v.property_id = ppv.property_id
WHERE
(ppv.property_id = 1 and v.value > $a and v.value < $b )
OR
(ppv.property_id = 2 and v.value > $c and v.value < $d )

First problem: what is t1 ?
Second problem:
t1.property_id = t2.property_id
t1.property_id = 1
t2.property_id = 2
Which means : 1 = 2.
If I understand well, you're looking for products which have :
a property_id = 1 set
a property_id = 2 set
a value superior to $a if property_id = 1 exists
a value superior to $c if property_id = 2 exists
a value inferior to $b if property_id = 1 exists
a value inferior to $d if property_id = 2 exists
I think you're looking for this request :
SELECT product_id
FROM v
JOIN ppv as t1 ON v.product_id = t1.product_id AND t1.property_id = 1
JOIN ppv as t2 ON v.product_id = t2.product_id AND t2.property_id = 2
WHERE v.value > GREATEST($a, $c)
AND v.value < LEAST($b, $d)

SELECT `product_id`,
CONVERT(GROUP_CONCAT(v.`property_id`) USING cp1251) as properties
FROM `values` as v INNER JOIN `product_property_values` as ppv
ON ppv.value_id = v.id
WHERE
(v.`property_id` = 1 and v.value >= 2500000 and v.value <= 3000000 )
or
(v.`property_id` = 2 and v.value >= 1 and v.value <= 3 )
GROUP by product_id
HAVING LOCATE('1', properties) and LOCATE('2', properties)
Th result:
test 1
v.`property_id` = 1 and v.value >= 2500000 and v.value < 3000000
v.`property_id` = 2 and v.value >= 1 and v.value <= 2
product_id properties
Empty
test2
v.`property_id` = 1 and v.value >= 2550000 and v.value < 3000000
v.`property_id` = 2 and v.value >= 1 and v.value <= 4
product_id properties
2 2,1
test3
v.`property_id` = 1 and v.value >= 2000000 and v.value < 3000000
v.`property_id` = 2 and v.value >= 1 and v.value <= 4
product_id properties
1 1,2
2 2,1
It's OK!

Related

MySql COUNT datediff values in complex function

I have this SQL Query that returns datediff of number of week
SELECT
ROUND(DATEDIFF((
SELECT t.date FROM actividad_newsletters t WHERE t.id_newsletter = t1.id_newsletter AND t1.id_desc = 3 AND (t.id_desc = 5 OR t.id_desc = 7) AND t.date > t1.date ORDER BY t.date LIMIT 1),
MIN(t1.date)
)/7, 0) as weeks
FROM actividad_newsletters t1
INNER JOIN newsletter t2 ON t1.id_newsletter = t2.id
GROUP BY id_newsletter
HAVING weeks IS NOT NULL
And gets this results:
0
0
0
0
0
1
1
1
1
1
1
2
2
3
3
3
3
3
3
3
3
3
3
3
.
.
.
117
117
118
119
119
I want do a count for same result like:
total week
----- ----
5 0
6 1
2 2
11 3
. .
. .
. .
2 117
1 118
2 119
How should I do it?
I tried with count(weeks) but isn't working
Try This
Select weeks, count(*) from (SELECT
ROUND(DATEDIFF((
SELECT t.date FROM actividad_newsletters t WHERE t.id_newsletter = t1.id_newsletter AND t1.id_desc = 3 AND (t.id_desc = 5 OR t.id_desc = 7) AND t.date > t1.date ORDER BY t.date LIMIT 1),
MIN(t1.date)
)/7, 0) as weeks
FROM actividad_newsletters t1
INNER JOIN newsletter t2 ON t1.id_newsletter = t2.id
GROUP BY id_newsletter
HAVING weeks IS NOT NULL) as t group by weeks
SOLVED:
SELECT weeks, COUNT(weeks) FROM (
SELECT
ROUND(DATEDIFF((
SELECT t.date FROM actividad_newsletters t WHERE t.id_newsletter = t1.id_newsletter AND t1.id_desc = 3 AND (t.id_desc = 5 OR t.id_desc = 7) AND t.date > t1.date ORDER BY t.date LIMIT 1),
MIN(t1.date)
)/7, 0) as weeks
FROM actividad_newsletters t1
INNER JOIN newsletter t2 ON t1.id_newsletter = t2.id
GROUP BY id_newsletter
HAVING weeks IS NOT NULL ) AS count GROUP BY weeks

Complex querying on table with multiple userids

I have a table like this:
score
id week status
1 1 0
2 1 1
3 1 0
4 1 0
1 2 0
2 2 1
3 2 0
4 2 0
1 3 1
2 3 1
3 3 1
4 3 0
I want to get all the id's of people who have a status of zero for all weeks except for week 3. something like this:
Result:
result:
id w1.status w2.status w3.status
1 0 0 1
3 0 0 1
I have this query, but it is terribly inefficient on larger datasets.
SELECT w1.id, w1.status, w2.status, w3.status
FROM
(SELECT s.id, s.status
FROM score s
WHERE s.week = 1) w1
LEFT JOIN
(SELECT s.id, s.status
FROM score s
WHERE s.week = 2) w2 ON w1.id=w2.id
LEFT JOIN
(SELECT s.id, s.status
FROM score s
WHERE s.week = 3) w3 ON w1.id=w3.id
WHERE w1.status=0 AND w2.status=0 AND w3.status=1
I am looking for a more efficient way to calculate the above.
select id
from score
where week in (1, 2, 3)
group by id
having sum(
case
when week in (1, 2) and status = 0 then 1
when week = 3 and status = 1 then 1
else 0
end
) = 3
Or more generically...
select id
from score
group by id
having
sum(case when status = 0 then 1 else 0 end) = count(*) - 1
and min(case when status = 1 then week else null end) = max(week)
You can do using not exists as
select
t1.id,
'0' as `w1_status` ,
'0' as `w2_status`,
'1' as `w3_status`
from score t1
where
t1.week = 3
and t1.status = 1
and not exists(
select 1 from score t2
where t1.id = t2.id and t1.week <> t2.week and t2.status = 1
);
For better performance you can add index in the table as
alter table score add index week_status_idx (week,status);
In case of static number of weeks (1-3), group_concat may be used as a hack..
Concept:
SELECT
id,
group_concat(status) as totalStatus
/*(w1,w2=0,w3=1 always!)*/
FROM
tableName
WHERE
totalStatus = '(0,0,1)' /* w1=0,w2=1,w3=1 */
GROUP BY
id
ORDER BY
week ASC
(Written on the go. Not tested)
SELECT p1.id, p1.status, p2.status, p3.status
FROM score p1
JOIN score p2 ON p1.id = p2.id
JOIN score p3 ON p2.id = p3.id
WHERE p1.week = 1
AND p1.status = 0
AND p2.week = 2
AND p2.status = 0
AND p3.week = 3
AND p3.status = 1
Try this, should work

If not found in record then get other where case in mysql

Need to check in where case that if not found where type='P' then it take record of type='C'
here is table
paper_id | product_id | type
1 1 P
2 1 P
3 1 C
4 1 C
5 2 C
6 2 C
There is product_id 1 and 2, need to get those record that have type='P' but those product who have not type='P' the record get from record type='C'
after query need this result
paper_id | product_id | type
1 1 P
2 1 P
5 2 C
6 2 C
i try
select * from table where CASE WHEN type !='P' THEN type='C' ELSE type='P'END
but not working
select paper_id, product_id, type from your_tab
where type = 'P'
union all
select t1.paper_id, t1.product_id, t1.type from your_tab t1
where t1.type = 'C'
and not exists (select 1 from your_tab t2
where t2.product_id = t1.product_id and t2.type = 'P');
maybe this will help
SELECT DISTINCT T.PRODUCT_ID, T.PAPER_ID, T.TYPE
FROM YOUR_TABLE T
WHERE (CASE
WHEN T.TYPE = 'P' THEN
'TRUE'
WHEN T.TYPE != 'P' THEN
(CASE
WHEN (SELECT COUNT(*)
FROM YOUR_TABLE T2
WHERE T2.PRODUCT_ID = T.PRODUCT_ID
AND T2.TYPE = 'P') = 0 THEN
'TRUE'
ELSE
'FALSE'
END)
END) = 'TRUE'

Mysql split row sum by count

I have the following tables
http://sqlfiddle.com/#!2/d0a3d
sp | product | exp
1 A | 50
1 B 50
1 A 100
1 B 100
2 B 200
2 C 200
3 A 50
3 B 50
Technical I want to divide exp to total number of products associated with t_id
The final result should be
sp | A | B | C
1 | 150 | 150 | 0
2 | 0 | 200 | 200
3 | 50 | 50 | 0
Can be done like this (done to match your sql fiddle columns):-
SELECT b.sp_id,
SUM(IF(a.product = 'A', b.exp, 0)) AS A,
SUM(IF(a.product = 'B', b.exp, 0)) AS B,
SUM(IF(a.product = 'C', b.exp, 0)) AS C
FROM topic_product a
INNER JOIN exp_speaker_topic b
ON a.t_id = b.t_id
GROUP BY b.sp_id
But a mess waiting to happen when extra values get added.
EDIT - amended to give what I think you are saying you want.
SELECT sp_id,
SUM(IF(product = 'A', avg_exp, 0)) AS A,
SUM(IF(product = 'B', avg_exp, 0)) AS B,
SUM(IF(product = 'C', avg_exp, 0)) AS C
FROM
(
SELECT sp_id, a.product, exp / Sub1.product_count AS avg_exp
FROM topic_product a
INNER JOIN exp_speaker_topic b
ON a.t_id = b.t_id
INNER JOIN
(
SELECT t_id, COUNT(*) AS product_count
FROM topic_product
GROUP BY t_id
) Sub1
ON a.t_id = Sub1.t_id
) Sub2
GROUP BY sp_id
SQL fiddle:-
http://sqlfiddle.com/#!2/d0a3d/33
OK, slow day. Just do the following, and handle missing results and display logic in the presentation layer/application-level code (e.g. a simple php loop acting upon an ordered array)...
SELECT p.product
, s.sp_id
, SUM(s.exp/x.cnt) total
FROM topic_product p
JOIN exp_speaker_topic s
ON s.t_id = p.t_id
JOIN
( SELECT t_id
, COUNT(0) cnt
FROM topic_product
GROUP
BY t_id
) x
ON x.t_id = p.t_id
GROUP
BY sp_id,product;
Here is the SQL Fiddle demonstrating the below queries.
You could also use CASE statements like the following:
SELECT e.sp_id,
SUM(CASE WHEN t.product = 'A' THEN e.exp ELSE 0 END) AS A,
SUM(CASE WHEN t.product = 'B' THEN e.exp ELSE 0 END) AS B,
SUM(CASE WHEN t.product = 'C' THEN e.exp ELSE 0 END) AS C
FROM topic_product t INNER JOIN exp_speaker_topic e ON t.t_id = e.t_id
GROUP BY e.sp_id;
If you want to divide by the number of record use the following:
SELECT e.sp_id,
SUM(CASE WHEN t.product = 'A' THEN e.exp ELSE 0 END) /
SUM(CASE WHEN t.product = 'A' THEN 1 ELSE 0 END) AS A,
SUM(CASE WHEN t.product = 'B' THEN e.exp ELSE 0 END) /
SUM(CASE WHEN t.product = 'B' THEN 1 ELSE 0 END) AS B,
SUM(CASE WHEN t.product = 'C' THEN e.exp ELSE 0 END) /
SUM(CASE WHEN t.product = 'C' THEN 1 ELSE 0 END) AS C
FROM topic_product t INNER JOIN exp_speaker_topic e ON t.t_id = e.t_id
GROUP BY e.sp_id;
If you want to get rid of the Nulls you could use the following:
SELECT m.sp_id,
CASE WHEN ISNULL(m.A) = 0 THEN m.A ELSE 0 END AS A,
CASE WHEN ISNULL(m.B) = 0 THEN m.B ELSE 0 END AS B,
CASE WHEN ISNULL(m.C) = 0 THEN m.C ELSE 0 END AS C
FROM
(
SELECT e.sp_id,
SUM(CASE WHEN t.product = 'A' THEN e.exp ELSE 0 END) / SUM(CASE WHEN t.product = 'A' THEN 1 ELSE 0 END) AS A,
SUM(CASE WHEN t.product = 'B' THEN e.exp ELSE 0 END) / SUM(CASE WHEN t.product = 'B' THEN 1 ELSE 0 END) AS B,
SUM(CASE WHEN t.product = 'C' THEN e.exp ELSE 0 END) / SUM(CASE WHEN t.product = 'C' THEN 1 ELSE 0 END) AS C
FROM topic_product t INNER JOIN exp_speaker_topic e ON t.t_id = e.t_id
GROUP BY e.sp_id
) AS m;

is this query COUNT is impossible?

I'm facing to very hard pb, i don"t find the way to achieve this, i want count how many occurence is equal to member1(id1) 's occurence , as you see here ,
id2 have 4 equal occurence of id1 and id3 have only 1 egual occurence:
my table test is :
id classement aptitude A B C
1 2440   oui 2 9 1
2 2440   oui 2 9 5
3 1760   oui 1 8 5
4 2440 oui 2 9 1
In this exemple ,result expeted should be :
id count
4 5
2 4
3 1
Whats kind of query could achieve it please, is it possible ?!
Try:
select T2.id,
coalesce((T1.classement=T2.classement),0)+
coalesce((T1.aptitude=T2.aptitude),0)+
coalesce((T1.A=T2.A),0)+
coalesce((T1.B=T2.B),0)+
coalesce((T1.C=T2.C),0) match_count
from Temp T1
cross join Temp T2
where T1.id = 1 and T2.id <> 1
order by 2 desc
SQLFiddle here.
Here is the Working DEMO of SQLFiddel
Below is the Sample Query
select T1.id,
(Case T1.classement
when T2.classement Then 1 Else 0
End)+
(Case T1.aptitude
when T2.aptitude Then 1 Else 0
End)+
(Case T1.A
when T2.A Then 1 Else 0
End)+
(Case T1.B
when T2.B Then 1 Else 0
End)+
(Case T1.C
when T2.C Then 1 Else 0
End) Count
from Temp T1,
(select *
from Temp
where id =1) T2
where T1.id <> 1
and (T1.classement = T2.classement
or T1.aptitude = T2.aptitude
or T1.A = T2.A
or T1.B = T2.B
or T1.C =T2.C)
order by 2 desc
This might work:
select a.id,
length((case when a.aptitude = b.aptitude then '1' else '' end) ||
(case when a.classement = b.classement then '1' else '' end) ||
(case when a.A = b.A then '1' else '' end) ||
(case when a.B = b.B then '1' else '' end) ||
(case when a.C = b.C then '1' else '' end)) count
from test a,
(select *
from test
where id = 1) b
where a.id != 1