I have a mysql table that Im trying to run a single/nested query on.
SELECT
`subscriber_id`,
(SELECT...?) AS total_campaigns,
(SELECT...?) AS total_opens,
(total_opens / total_campaigns) as percentage
FROM
`campaigns_table`
The type column with a value = 2 shows that the campaign was opened.
Im looking to return a result set with all subscriber_id's that has the total campaigns and total opens
Query Result Data
+---------------+-----------------+-------------+------------+
| subscriber_id | total_campaigns | total_opens | percentage |
+---------------+-----------------+-------------+------------+
| 1 | 2 | 1 | 0.5 |
| 2 | 2 | 2 | 1.0 |
| 3 | 2 | 0 | 0.0 |
| 4 | 1 | 0 | 0.0 |
| 5 | 1 | 1 | 1.0 |
+---------------+-----------------+-------------+------------+
subscriber_id 1 would be total_campaigns = 2 ( campaign_id's 37428,37239 ) and total_opens = 1 ( only campaign_id 27428 has a type 2 record )
Example Table Data
+---------------+-------------+------------+-------+------+---------+
| subscriber_id | campaign_id | timestamp | count | type | link_id |
+---------------+-------------+------------+-------+------+---------+
| 1 | 37428 | 1434513738 | 1 | 1 | 0 |
| 1 | 37428 | 1434513758 | 1 | 1 | 0 |
| 1 | 37428 | 1434513338 | 2 | 2 | 0 |
| 1 | 37429 | 1434511738 | 1 | 1 | 0 |
| 1 | 37429 | 1434311738 | 1 | 1 | 1 |
| 2 | 37428 | 1534513738 | 1 | 1 | 0 |
| 2 | 37428 | 1534513758 | 1 | 1 | 0 |
| 2 | 37428 | 1534513338 | 2 | 2 | 0 |
| 2 | 37429 | 1534511738 | 1 | 1 | 1 |
| 2 | 37429 | 1534311738 | 1 | 2 | 0 |
| 3 | 37428 | 1534513738 | 1 | 1 | 0 |
| 3 | 37429 | 1534511738 | 1 | 1 | 1 |
| 4 | 57428 | 1534513738 | 1 | 1 | 0 |
| 4 | 57428 | 1534513758 | 1 | 1 | 0 |
| 5 | 57428 | 1534513338 | 3 | 2 | 0 |
+---------------+-------------+------------+-------+------+---------+
Using the answer from #spencer7593 below. How can I then use the results to update another table?
trying to do something like this (it doesn't work how I have it)
UPDATE `subscribers` a
LEFT JOIN `campaigns_table` b ON a.`ID` = b.`subscriber_id`
SET a.`STATUS` = 2
FROM(
SELECT t.subscriber_id
, COUNT(DISTINCT t.campaign_id) AS total_campaigns
, COUNT(DISTINCT IF(t.type=2,t.campaign_id,NULL)) AS open_campaigns
, COUNT(DISTINCT IF(t.type=2,t.campaign_id,NULL))
/ COUNT(DISTINCT t.campaign_id) AS percentage
FROM `campaigns_table` t
GROUP BY t.subscriber_id
HAVING COUNT(DISTINCT t.campaign_id) > 5 AND COUNT(DISTINCT IF(t.type=2,t.campaign_id,NULL)) = 0
ORDER BY t.subscriber_id
) i
It looks to me like a problem that can be addressed with conditional aggregation, with a single pass through the table, with no need for any nested queries.
SELECT t.subscriber_id
, COUNT(DISTINCT t.campaign_id) AS total_campaigns
, COUNT(DISTINCT IF(t.type=2,t.campaign_id,NULL)) AS open_campaigns
, COUNT(DISTINCT IF(t.type=2,t.campaign_id,NULL))
/ COUNT(DISTINCT t.campaign_id) AS percentage
FROM `campaigns_table` t
GROUP BY t.subscriber_id
ORDER BY t.subscriber_id
It is possible to generate an equivalent result with nested queries, but in general, a single pass through the table (with a single SELECT) will have a more efficient access plan.
If there's a requirement to use nested queries (I don't understand why there would be), in general, I'd prefer to use inline views over correlated queries in the SELECT list.
SELECT q.subscriber_id
, SUM(1) AS total_campaigns
, SUM(q.open_campaign) AS open_campaigns
, SUM(q.open_campaign)/SUM(1) AS percentage
FROM ( SELECT t.subscriber_id
, t.campaign
, MAX(t.type=2) AS `open_campaign`
FROM `campaigns_table` t
WHERE t.campaign IS NOT NULL
GROUP
BY t.subscriber_id
, t.campaign
) q
ORDER BY q.subscriber
If we want to use nested queries in the SELECT list, those would be correlated subqueries...
SELECT s.subscriber
, ( SELECT COUNT(DISTINCT t.campaign)
FROM `campaigns_table` t
WHERE t.subscriber = s.subscriber
) AS total_campaigns
, ( SELECT COUNT(DISTINCT o.campaign)
FROM `campaigns_table` o
WHERE o.subscriber = s.subscriber
AND o.type=2
) AS open_campaigns
, ( SELECT COUNT(DISTINCT po.campaign)
FROM `campaigns_table` po
WHERE po.subscriber = s.subscriber
AND po.type=2
)
/ ( SELECT COUNT(DISTINCT pt.campaign)
FROM `campaigns_table` pt
WHERE pt.subscriber = s.subscriber
) AS percentage
FROM ( SELECT r.subscriber
FROM `campaigns_table` r
GROUP BY r.subscriber
) s
ORDER BY s.subscriber
Related
I am looking to get all values from first table along with joinned values from second table.
Table 1 is fee_category with fields:
id | Category
1 | A
2 | B
3 | C
4 | D
Table 2 is fee_charge with fields:
id | std_id | particularID | CategoryID | assign | amount
1 | 1 | 1 | 1 | 0 | 1000
2 | 1 | 1 | 2 | 1 | 12000
3 | 1 | 2 | 3 | 0 | 3000
4 | 1 | 2 | 4 | 0 | 10
5 | 2 | 1 | 2 | 0 | 100
6 | 2 | 2 | 3 | 0 | 120
Base table is "fee_category" from which I need all values left joining with "fee_charge" from where I need values or NULL for a particular std_id and particularID
SELECT fee_category.id, fee_category.Category, fee_charge.std_id
, fee_charge.particularID, fee_charge.CategoryID, fee_charge.assign, fee_charge.amount FROM fee_category
LEFT join fee_charge on fee_category.id=fee_charge.CategoryID
where (fee_charge.std_id = 1 OR fee_charge.std_id IS NULL)
AND (fee_charge.particularID = 1 OR fee_charge.particularID IS NULL)
group By fee_category.id
order By fee_charge.assign DESC
Here I am trying to get all categories of std_id=1 and particularID=1
Correct result should be
id | Category | std_id | particularID | CategoryID | assign | amount
1 | A | 1 | 1 | 1 | 0 | 1000
1 | B | 1 | 1 | 2 | 1 | 12000
1 | C | 1 | NULL | NULL | NULL | NULL
1 | D | 1 | NULL | NULL | NULL | NULL
I am trying various versions of the above query but not getting proper result. Please help
SELECT fee_category.id
, fee_category.Category
, X.std_id
, X.particularID
, X.CategoryID
, X.assign
, X.amount
FROM fee_category
LEFT JOIN
(SELECT * FROM fee_charge
WHERE fee_charge.std_id = 1
AND fee_charge.particularID = 1) AS X
ON x.CategoryID = fee_category.id
It's very hard to follow when the fiddle doesn't match the question, so I may have misunderstood, but perhaps you're after something like this...
SELECT x.id
, z.category
, x.std_id
, y.particularID
, y.categoryID
, y.assign
, y.amount
FROM fee_charge x
LEFT
JOIN fee_charge y
ON y.id = x.id
AND y.particularID = 1
JOIN fee_category z
ON z.id = x.categoryID
WHERE x.std_id = 1;
I have table it store hierarchy data in MySQL this table store stable relation but if each user less than 1000 buy removed and user User a lower level replace this is my code and work fine, after GROUP BY it contain all ancestor of descendant with compare then COUNT(*) AS level count level each user. This I have SQL code to compress data According to minimum buy for each user
+-------------+---------------+-------------+
| ancestor_id | descendant_id | path_length |
+-------------+---------------+-------------+
| 1 | 1 | 0 |
| 1 | 2 | 1 |
| 1 | 3 | 1 |
| 1 | 4 | 2 |
| 1 | 5 | 3 |
| 1 | 6 | 4 |
| 2 | 2 | 0 |
| 2 | 4 | 1 |
| 2 | 5 | 2 |
| 2 | 6 | 3 |
| 3 | 3 | 0 |
| 4 | 4 | 0 |
| 4 | 5 | 1 |
| 4 | 6 | 2 |
| 5 | 5 | 0 |
| 5 | 6 | 1 |
| 6 | 6 | 0 |
+-------------+---------------+-------------+
This is table buy
+--------+--------+
| userid | amount |
+--------+--------+
| 2 | 2000 |
| 4 | 6000 |
| 6 | 7000 |
| 1 | 7000 |
SQL code
SELECT a.*
FROM
( SELECT userid
FROM webineh_user_buys
GROUP BY userid
HAVING SUM(amount) >= 1000
) AS buys_d
JOIN
webineh_prefix_nodes_paths AS a
ON a.descendant_id = buys_d.userid
JOIN
(
SELECT userid
FROM webineh_user_buys
GROUP BY userid
HAVING SUM(amount) >= 1000
) AS buys_a on (a.ancestor_id = buys_a.userid )
JOIN
( SELECT descendant_id
, MAX(path_length) path_length
FROM webineh_prefix_nodes_paths
where a.ancestor_id = ancestor_id
GROUP
BY descendant_id
) b
ON b.descendant_id = a.descendant_id
AND b.path_length = a.path_length
GROUP BY a.descendant_id, a.ancestor_id
I need get max path_length where ancestor_id have At least 1000 amount buy but have error in where in subquery where a.ancestor_id = ancestor_id error code
1054 - Unknown column 'a.ancestor_id' in 'where clause'
I add SQLFidle demo.
You could use this query:
select m.userid as descendant,
p.ancestor_id,
p.path_length
from (
select b1.userid,
min(case when b2.amount >= 1000
then p.path_length
end) as path_length
from (select userid, sum(amount) amount
from webineh_user_buys
group by userid
having sum(amount) >= 1000
) as b1
left join webineh_prefix_nodes_paths p
on p.descendant_id = b1.userid
and p.path_length > 0
left join (select userid, sum(amount) amount
from webineh_user_buys
group by userid) as b2
on p.ancestor_id = b2.userid
group by b1.userid
) as m
left join webineh_prefix_nodes_paths p
on p.descendant_id = m.userid
and p.path_length = m.path_length
order by m.userid
Output for sample data in the question:
| userid | ancestor_id | path_length |
|--------|-------------|-------------|
| 1 | (null) | (null) |
| 2 | 1 | 1 |
| 4 | 2 | 1 |
| 6 | 4 | 2 |
SQL fiddle
I have a query and a result as follows.
In the database NULL and 0 represent the same meaning.
Now I want a counter based on Null+0 or 1
Eg:in the following example I want the result like this:
IsVirtual Category counter
NULL+0 3 343+8 = (351 is Total)
Query
select * from
(
Select IsVirtual, Category, count(*) as counter
from [Hardware]
group by IsVirtual, Category
) innercat
Output
+-----------+----------+---------+
| IsVirtual | Category | counter |
+-----------+----------+---------+
| NULL | 3 | 343 |
| 0 | 3 | 8 |
| 1 | 2 | 1 |
| 0 | 1 | 1 |
| NULL | 6 | 119 |
| 0 | 4 | 1 |
| NULL | 1 | 70 |
| 0 | 5 | 9 |
| NULL | 4 | 54 |
| 0 | 2 | 2 |
| NULL | 5 | 41 |
| NULL | 2 | 112 |
| 1 | 1 | 5 |
+-----------+----------+---------+
I think you want this :
SELECT COALESCE(IsVirtual, 0) as [IsVirtual],
Category,
Count(*) as [Counter]
FROM yourtable
GROUP BY COALESCE(IsVirtual, 0),Category
This will give you expected result without using subquery.
try with this
select * from (
Select CASE ISNULL(IsVirtual,0)
WHEN 0 Then 'NULL + 0'
ELSE IsVirtual
END AS IsVirtual, Category, count(*) as counter from [Hardware] group by ISNULL(IsVirtual,0), Category
)innercat
You can also do the same thing by using MAX function
This might help you.
SELECT
max(IsVirtual) as IsVirtual,
Category,
Count(*) as Counter
FROM
yourtable
GROUP BY
Category
how i can GROUP BY entry_category if entry_category > 0
| entry_id | entry_title | entry_category |
-------------------------------
| 1 | xxx | 6 |
| 2 | xxx | 4 |
| 3 | xxx | 6 |
| 4 | xxx | 0 |
| 5 | xxx | 0 |
| 6 | xxx | 6 |
| 7 | xxx | 4 |
| 8 | xxx | 7 |
I want entrys category is set , not show duplicate :
| 1 | xxx | 6 |
| 2 | xxx | 4 |
| 4 | xxx | 0 |
| 5 | xxx | 0 |
| 8 | xxx | 7 |
Here is a way to do it, but there may be better way to do it. I took table name as test
select
entry_id,
entry_title,
entry_category
from
(
(
select
t1.entry_id,
t1.entry_title,
t1.entry_category
from test t1
left join test t2
on t1.entry_category = t2.entry_category
AND t1.entry_id < t2.entry_id
where t1.entry_category <> 0
group by t1.entry_category
)
union all
(
select entry_id,entry_title,entry_category from test
where entry_category = 0
)
)x
order by entry_id
DEMO
this is very good worked for me :
SELECT * FROM entrys
WHERE entry_category> 0
GROUP BY entry_category
UNION
SELECT * FROM entrys
WHERE entry_category= 0
good worked.
I've got four MySQL tables:
users (id, name)
polls (id, text)
options (id, poll_id, text)
responses (id, poll_id, option_id, user_id)
Given a particular poll and a particular option, I'd like to generate a table that shows which options from other polls are most strongly correlated.
Suppose this is our data set:
TABLE users:
+------+-------+
| id | name |
+------+-------+
| 1 | Abe |
| 2 | Bob |
| 3 | Che |
| 4 | Den |
+------+-------+
TABLE polls:
+------+-----------------------+
| id | text |
+------+-----------------------+
| 1 | Do you like apples? |
| 2 | What is your gender? |
| 3 | What is your height? |
| 4 | Do you like polls? |
+------+-----------------------+
TABLE options:
+------+----------+---------+
| id | poll_id | text |
+------+----------+---------+
| 1 | 1 | Yes |
| 2 | 1 | No |
| 3 | 2 | Male |
| 4 | 2 | Female |
| 5 | 3 | Short |
| 6 | 3 | Tall |
| 7 | 4 | Yes |
| 8 | 4 | No |
+------+----------+---------+
TABLE responses:
+------+----------+------------+----------+
| id | poll_id | option_id | user_id |
+------+----------+------------+----------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 2 |
| 3 | 1 | 2 | 3 |
| 4 | 1 | 2 | 4 |
| 5 | 2 | 3 | 1 |
| 6 | 2 | 3 | 2 |
| 7 | 2 | 3 | 3 |
| 8 | 2 | 4 | 4 |
| 9 | 3 | 5 | 1 |
| 10 | 3 | 6 | 2 |
| 10 | 3 | 5 | 3 |
| 10 | 3 | 6 | 4 |
| 10 | 4 | 7 | 1 |
| 10 | 4 | 7 | 2 |
| 10 | 4 | 7 | 3 |
| 10 | 4 | 7 | 4 |
+------+----------+------------+----------+
Given the poll ID 1 and the option ID 2, the generated table should be something like this:
+----------+------------+-----------------------+
| poll_id | option_id | percent_correlated |
+----------+------------+-----------------------+
| 4 | 7 | 100 |
| 2 | 3 | 66.66 |
| 3 | 6 | 66.66 |
| 2 | 4 | 33.33 |
| 3 | 5 | 33.33 |
| 4 | 8 | 0 |
+----------+------------+-----------------------+
So basically, we're identifying all of the users who responded to poll ID 1 and selected option ID 2, and we're looking through all the other polls to see what percentage of them also selected each other option.
Don't have an instance handy to test, can you see if this gets proper results:
select
poll_id,
option_id,
((psum - (sum1 * sum2 / n)) / sqrt((sum1sq - pow(sum1, 2.0) / n) * (sum2sq - pow(sum2, 2.0) / n))) AS r,
n
from
(
select
poll_id,
option_id,
SUM(score) AS sum1,
SUM(score_rev) AS sum2,
SUM(score * score) AS sum1sq,
SUM(score_rev * score_rev) AS sum2sq,
SUM(score * score_rev) AS psum,
COUNT(*) AS n
from
(
select
responses.poll_id,
responses.option_id,
CASE
WHEN user_resp.user_id IS NULL THEN SELECT 0
ELSE SELECT 1
END CASE as score,
CASE
WHEN user_resp.user_id IS NULL THEN SELECT 1
ELSE SELECT 0
END CASE as score_rev,
from responses left outer join
(
select
user_id
from
responses
where
poll_id = 1 and
option_id = 2
)user_resp
ON (user_resp.user_id = responses.user_id)
) temp1
group by
poll_id,
option_id
)components
After a few hours of trial and error, I managed to put together a query that works correctly:
SELECT poll_id AS p_id,
option_id AS o_id,
COUNT(*) AS optCount,
(SELECT COUNT(*) FROM response WHERE option_id = o_id AND user_id IN
(SELECT user_id FROM response WHERE poll_id = '1' AND option_id = '2')) /
(SELECT COUNT(*) FROM response WHERE poll_id = p_id AND user_id IN
(SELECT user_id FROM response WHERE poll_id = '1' AND option_id = '2'))
AS percentage
FROM response
INNER JOIN
(SELECT user_id FROM response WHERE poll_id = '1' AND option_id = '2') AS user_ids
ON response.user_id = user_ids.user_id
WHERE poll_id != '1'
GROUP BY option_id DESC
ORDER BY percentage DESC, optCount DESC
Based on a tests with a small data set, this query looks to be reasonably fast, but I'd like to modify it so the "IN" subquery is not repeated three times. Any suggestions?
This seems to give the right results for me:
select poll_stats.poll_id,
option_stats.option_id,
(100 * option_responses / poll_responses) as percent_correlated
from (select response.poll_id,
count(*) as poll_responses
from response selecting_response
join response on response.user_id = selecting_response.user_id
where selecting_response.poll_id = 1 and selecting_response.option_id = 2
group by response.poll_id) poll_stats
join (select options.poll_id,
options.id as option_id,
count(response.id) as option_responses
from options
left join response on response.poll_id = options.poll_id
and response.option_id = options.id
and exists (
select 1 from response selecting_response
where selecting_response.user_id = response.user_id
and selecting_response.poll_id = 1
and selecting_response.option_id = 2)
group by options.poll_id, options.id
) as option_stats
on option_stats.poll_id = poll_stats.poll_id
where poll_stats.poll_id <> 1
order by 3 desc, option_responses desc