Counting results of join on duplicate field - mysql

I have a table1 containing duplicate column value
Table1
id code
1 201202 0000 1111
2 201202 0000 9999
3 201203 0000 9999
4 201203 0000 0999
5 201204 1000 1999
6 201204 2000 2999
7 201205 3000 3999
8 201205 4000 4999
9 201205 5000 5999
Table 2
id numbers
1 2012020010
2 2012024929
3 2012033838
4 2012052434
5 2012052229
6 2012052232
I want to count all the numbers in table2 that are substring of distinct code in table 1
i.e. result should be
code frequency
201202 2
201203 1
201205 3
I have been able to get all the numbers for every code but can't figure out how to count them
SELECT DISTINCT table1.code , table1.id, table2.number AS ph_npa, count( * )
FROM table1
INNER JOIN table2 ON substr( table2.number, 1, 6 ) = table1.code
GROUP BY table1.number
any help is appreciated.

SELECT t1.code, COUNT(*) AS frequency
FROM table_one AS t1
LEFT JOIN table_two AS t2
ON t2.numbers LIKE CONCAT(t1.code, '%')
GROUP BY t1.code
Either use LEFT JOIN or INNER JOIN depending on if you want rows with frequency = 0 or not. All I did was basicly to run a LIKE as join condition with the % wildcard.

Try out the following. It can have performance hits on large data sets, but will get you started. It is working with my test data.
SELECT SUBSTR(t2.numbers, 1,6) AS CODE, COUNT(*) AS frequency
FROM table_2 t2
WHERE SUBSTR(t2.numbers, 1,6) IN (SELECT t1.code FROM table_1 t1)
GROUP BY SUBSTR(t2.numbers, 1,6)
Let me know if its working!

I'm not really one for using the "inner join" syntax and prefer to just use the cleaner looking implicit join on the data.
select
count(*)
from
npanxxsmall n, phone_numbers p
where
substr(n.code, 1, 6) = substr(p.number, 1, 6);
Let me know if this works!

ok I got it working and query is super fast
SELECT
DISTINCT A.code as code,
B.Counts AS frequency
FROM table1 AS A
INNER JOIN (
SELECT substr( number, 1, 6 ) AS subnumber, count( 1 ) AS Counts
FROM table2
GROUP BY substr( number, 1, 6 )
)
AS B ON A.code = B.subnumber
i.e.
select the number and frequency of number from table 2
and then join with distinct code form table 1

Related

MySQL - select rows where count in joined table equals 1

I need to select the rows from table "web_users" only if rows of another joined table called "web_users_branches" equals to 1.
What I have now:
SELECT id, code from web_users
JOIN
(
SELECT client_code
FROM web_users_branches
HAVING COUNT(*) = 1
) as t2
ON web_users.code = t2.client_code;
I get empty result.
Database example:
Web Users table:
id code
1 0001
2 0002
3 0003
Web Users Branches table:
id client_code
1 0001
2 0001
3 0002
4 0003
5 0003
Now after this query I should get only the user which client_code is 0002, because all the other user client_code count is not equal to 1 (there is x2 0003 and x2 0001). Any ideas?
I think you just want a group by in the subquery:
SELECT u.id, u.code
FROM web_users u JOIN
(SELECT client_code
FROM web_users_branches
GROUP BY client_code
HAVING COUNT(*) = 1
) c
ON u.code = c.client_code;
SELECT id, code
FROM web_users_branches as t1
JOIN web_users as t2
ON t2.code = t1.client_code
HAVING COUNT(*) = 1
should work. After an inner join, you only get a single row when both(!) tables have exactly one record in the beginning.

I want to have Sum of individual columns of two different table and show it in a single query result where customer id matches?

Create or replace view cnPointsDetailsvw
as select sum(cd.value), sum(cd1.points)
from customerdetails cd left join
customerdetails1 cd1 on cd.customerid = cd1.customerid;
The problem is that the above query is calculating sum multiple times for the column cd1.points
If table customerdetails1 has only 1 row, so why you use SUM() function?
Just use MAX().
I am confused of your table, so let me give a sample structurs and data.
table1
id points
-----------
1 10
2 20
3 40
table2
id points
-----------
1 10
1 2
1 4
2 20
3 40
3 5
And your query should be looks like this :
CREATE OR REPLACE VIEW view_name AS
SELECT t1.id,max(t1.points) as points1, sum(t2.points) as points2
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id
GROUP BY t1.id
Your view should be looks like this :
id points1 points2
---------------------
1 10 16
2 20 20
3 30 45
Do the calculation in subqueries, then join their results:
SELECT
CD.sum_value, CD1.sum_points
FROM
(SELECT sum(value) as sum_value FROM customerdetails) CD
INNER JOIN (SELECT sum(points) AS sum_points FROM customerdetails1) CD1
ON 1 = 1
Please note, that SUM() returns NULL if there were no matching rows, so the subqueries will return with exactly one record -> any ON condition will be fine which results to true.
If you want to group by customers, then do the grouping in the subqueries:
SELECT
CD.customerid, CD.sum_value, CD1.sum_points
FROM
(
SELECT customerid, sum(value) as sum_value
FROM customerdetails
GROUP BY customerid
) CD
LEFT JOIN
(
SELECT customerid, sum(points) AS sum_points
FROM customerdetails1
GROUP BY customerid
) CD1
ON CD.customerid = CD1.customerid
UPDATE
To create a view (and bypass the limitation of MySQL), you have to create 3 views: 2 for the 2 subresults, 1 to join their results:
CREATE VIEW customer_value AS
SELECT SUM(value) as sum_value FROM customerdetails;
CREATE VIEW customer_points AS
SELECT SUM(points) as sum_points FROM customerdetails1;
CREATE VIEW cnPointsDetailsvw AS
SELECT cv.sum_value, cp.sum_points
FROM customer_value cv
INNER JOIN customer_points cp
ON 1=1;

SQL - How to calculate column value and join with another table

As I am not good with MySQL query's so I wish someone help me for creating this kind of sql query.
I having two MySQL tables which is describe bellow:
Table Name: rating
-------------------
property_id user_id area_rate_count safety_rate_count friendly_rate_count walkability_rate_count
4 28 1 1 1 2
5 38 2 3 4 1
5 40 2 2 3 1
6 40 2 3 1 4
10 43 2 2 3 1
Table Name: listing
-------------------
property_id title
4 Sample 1
5 Sample 2
6 Sample 3
10 Sample 4
11 Sample 5
12 Sample 6
Now first I want to sum each column and divide. (area_rate_count, safety_rate_count, friendly_rate_count, walkability_rate_count). For example In property_id:5 having two times so first calculate column sum and divide by 2.
After calculation we will get this output:
Table Name: rating (After Calculation)
--------------------------------------
property_id rate
4 5
5 9 (Divided by 2 because this property_id is two times in table)
6 10
10 8
And Finally I want join this result to my listing table and result looks something like this:
Table Name: listing
-------------------
property_id title rate
4 Sample 1 5
5 Sample 2 9 (Divided by 2 becouse property_id is two times in table)
6 Sample 3 10
10 Sample 4 8
11 Sample 5 0
12 Sample 6 0
Thanks.
I think you want the avg() aggregation function along with a join:
select l.property_id, l.title,
coalesce(avg(area_rate_count + safety_rate_count + friendly_rate_count + walkability_rate_count
), 0) as rate
from listing l left outer join
property_id p
on l.property_id = p.property_id
group by l.property_id, l.title ;
If I understood it right I think you need this:
select l.property_id, l.title, coalesce(r.ssum/if(r.ct=0,1,r.ct), 0) as rate
from listing l LEFT JOIN
(select property_id,
sum(area_rate_count+safety_rate_count
+friendly_rate_count+walkability_rate_count) ssum,
count(*) ct
from rating
group by property_id ) r
ON l.property_id = r.property_id
order by l.property_id
See it here on fiddle: http://sqlfiddle.com/#!2/589d6/5
Edit
As OP asked on the comments that he wants all columns from listing here is what he want:
select l.*, coalesce(r.ssum/if(r.ct=0,1,r.ct), 0) as rate
from listing l LEFT JOIN
(select property_id,
sum(area_rate_count+safety_rate_count
+friendly_rate_count+walkability_rate_count) ssum,
count(*) ct
from rating
group by property_id ) r
ON l.property_id = r.property_id
order by l.property_id
CREATE TEMPORARY TABLE IF NOT EXISTS
temp_table ( INDEX(col_2) )
ENGINE=MyISAM
AS (
SELECT
property_id,
AVG(area_rate_count) as area_rate_count,
AVG(safety_rate_count) as safety_rate_count,
AVG(friendly_rate_count) as friendly_rate_count,
AVG(walkability_rate_count) as walkability_rate_count
FROM rating
GROUP BY property_id
)
SELECT * FROM listing L
JOIN temp_table T
ON L.property_id = T.property_id
Use the below statement to get distinct property_id with its own rate
select property_id, sum(separaterating)/count(property_id) from (
select property_id,sum(area_rate_count , safety_rate_count , friendly_rate_count , walkability_rate_count) as separaterating from rating group by property_id AS temp ) group by
property_id
you can then join with the other table to get the final result as below
select * from ( select property_id, sum(separaterating)/count(property_id) from (
select property_id,sum(area_rate_count , safety_rate_count , friendly_rate_count , walkability_rate_count) as separaterating from rating group by property_id AS temp ) group by
property_id) AS A inner join listing AS B on A.property_id = B.property_id
try this:
select a.prop_id as property_id, l.title, a.allratings / b.numberofreviews as rate
from
(
select property_id as prop_id, SUM(coalesce(area_rate_count,0) + coalesce(safety_rate_count,0) + coalesce(friendly_rate_count,0) + coalesce(walkability_rate_count,0)) as allratings
from rating
group by property_id
) a inner join
(
select property_id, count(distinct user_id) as numberofreviews
from rating
group by property_id
) b on a.property_id = b.property_id
inner join listing l on a.property_id = l.property_id
Try This Query
select ls.property_id,ls.title,inr.rate from listing as ls
left join
(select r.property_id as pid,r.rate/r.cnt as rate from
(select property_id,user_id,(area_rate_count+safefty_rate_count+friendly_rate_count+walkability_rate_count) as rate,count(*) as cnt from rating group by property_id) as r) as inr on inr.pid=ls.property_id

Group dates based on variable periods

i have two tables as follows------
table-1
CalenderType periodNumber periodstartdate
1 1 01-01-2013
1 2 11-01-2013
1 3 15-01-2013
1 4 25-01-2013
2 1 01-01-2013
2 2 15-01-2013
2 3 20-01-2013
2 4 25-01-2013
table2
Incidents Date
xyz 02-01-2013
xxyyzz 03-01-2013
ccvvb 12-01-2013
vvfg 16-01-2013
x3 17-01-2013
x5 24-01-2013
Now i want to find out the number of incidents took place in a given period(the Calendar type may change on runtime like)
the query should look something like this
select .......
from ......
where CalendarType=1
which should return
CalendarType PeriodNumber Incidents
1 1 2
1 2 1
1 3 3
1 4 0
can someone suggest me an approach or any method how this can be achieved.
Note:each period is variable in size.peroid1 may have 10 days period2 may have 5 days etc.
I think this does what you want, although I don't understand how you arrived at your sample output:
select t.CalenderType, t.periodNumber, count(*) as Incidents
from Table1 t
inner join (
select t2.Date, t2.Incidents, max(t1.periodstartdate) as PeriodStartDate
from Table2 t2
inner join Table1 t1 on t2.Date >= t1.periodstartdate
where CalenderType = 1
group by t2.Date, t2.Incidents
) a on t.periodstartdate = a.PeriodStartDate
where CalenderType=1
group by t.CalenderType, t.periodNumber
SQL Fiddle Example
Try this, a bit more general solution,SQLFiddle (Thanks RedFilter for schema):
SELECT t1.CalenderType, t1.periodNumber, count(Incidents)
FROM Table1 t1, Table1 t11, Table2
WHERE
(
(
t1.CalenderType = t11.CalenderType
AND t1.periodNumber = t11.periodNumber - 1
AND Date BETWEEN t1.periodstartdate AND t11.periodstartdate
)
OR
(
t1.periodNumber = (SELECT MAX(periodNumber) FROM Table1 WHERE t1.CalenderType = CalenderType)
AND Date > t1.periodstartdate
)
)
GROUP BY t1.CalenderType, t1.periodNumber
ORDER BY t1.CalenderType, t1.periodNumber

SQL: finding differences between rows

I want to count how many times each user has rows within '5' of eachother.
For example, Don - 501 and Don - 504 should be counted, while Don - 501 and Don - 1600 should not be counted.
Start:
Name value
_________ ______________
Don 1235
Don 6012
Don 6014
Don 6300
James 9000
James 9502
James 9600
Sarah 1110
Sarah 1111
Sarah 1112
Sarah 1500
Becca 0500
Becca 0508
Becca 0709
Finish:
Name difference_5
__________ _____________
Don 1
James 0
Sarah 2
Becca 0
Use the ABS() function, in conjunction with a self-join in a subquery:
So, something like:
SELECT name, COUNT(*) / 2 AS difference_5
FROM (
SELECT a.name name, ABS(a.value - b.value)
FROM tbl a JOIN tbl b USING(name)
WHERE ABS(a.value - b.value) BETWEEN 1 AND 5
) AS t GROUP BY name
edited as per Andreas' comment.
Assuming that each name -> value pair is unique, this will get you the count of times the value is within 5 per name:
SELECT a.name,
COUNT(b.name) / 2 AS difference_5
FROM tbl a
LEFT JOIN tbl b ON a.name = b.name AND
a.value <> b.value AND
ABS(a.value - b.value) <= 5
GROUP BY a.name
As you'll notice, we also have to exclude the pairs that are equal to themselves.
But if you wanted to count the number of times each name's values came within 5 of any value in the table, you can use:
SELECT a.name,
COUNT(b.name) / 2 AS difference_5
FROM tbl a
LEFT JOIN tbl b ON NOT (a.name = b.name AND a.value = b.value) AND
ABS(a.value - b.value) <= 5
GROUP BY a.name
See the SQLFiddle Demo for both solutions.
Because the OP also wants de zero counts, we'll need a self- left join. Extra logic is needed if one person has two exactly the same values, these should also be counted only once.
WITH cnts AS (
WITH pair AS (
SELECT t1.zname,t1.zvalue
FROM ztable t1
JOIN ztable t2
ON t1.zname = t2.zname
WHERE ( t1.zvalue < t2.zvalue
AND t1.zvalue >= t2.zvalue - 5 )
OR (t1.zvalue = t2.zvalue AND t1.ctid < t2.ctid)
)
SELECT DISTINCT zname
, COUNT(*) AS znumber
FROM pair
GROUP BY zname
)
, names AS (
SELECT distinct zname AS zname
FROM ztable
GROUP BY zname
)
SELECT n.zname
, COALESCE(c.znumber,0) AS znumber
FROM names n
LEFT JOIN cnts c ON n.zname = c.zname
;
RESULT:
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 14
zname | znumber
-------+---------
Sarah | 3
Don | 1
Becca | 0
James | 0
(4 rows)
NOTE: sorry for the CTE, I had not seen th mysql tag,I just liked the problem ;-)
SELECT
A.Name,
SUM(CASE WHEN (A.Value < B.Value) AND (A.Value >= B.Value - 5) THEN 1 ELSE 0 END) Difference_5
FROM
tbl A INNER JOIN
tbl B USING(Name)
GROUP BY
A.Name