find top 3 values with an inner join - php

I have a table called users_preferred_zips that looks like this:
username | price | zip | program | active
-----------+---------+---------+-----------+---------
joe | 5 | 92108 | dog | 1
tom | 7 | 92108 | dog | 1
mary | 5 | 92108 | dog | 1
paul | 6 | 92108 | dog | 1
ron | 6 | 92108 | dog | 1
I have another table called users that looks like this
username | balance
-----------+----------
joe | 10
tom | 12
mary | 2
paul | 14
ron | 3
I need a query to pull AND sum the 3 highest values from the users_preferred_zips table where the username from the users table has a balance value greater than or equal to 5. I know i need to do some sort of inner join but my query below is not working. Here is the query i have:
SELECT SUM(price) AS SumOfTopValues
FROM (
SELECT users_preferred_zips . * , users.last_purchase, users.lesson_type, users.pref_acct_balance
INNER JOIN users ON ( users_preferred_zips.username = users.username )
WHERE users_preferred_zips.zip = '92108'
AND users_preferred_zips.program = 'dog'
AND users_preferred_zips.active = 1
AND users.pref_acct_balance >= '5'
ORDER BY price DESC
LIMIT 3
) AS sub
So the correct query would pull the following:
3 highest:
joe | 5
tom | 7
paul | 6
Sum of 3 highest values = 18
I feel like this should be pretty simple but i'm having a tough time! Thanks for your help

You can check this using:
SELECT SUM(price) AS SumOfTopValues
FROM users_preferred_zips
WHERE username IN (
SELECT username
FROM users
WHERE pref_acct_balance >= 5
)

Related

Confusing about group and having clause with php

I need to get all IDs from table A where all the Expiry date from Table B (INNER JOIN ID = A_ID) are < today (2018-06-29) but i'm not sure and a bit confusing for the query.
Based on my example (2018-06-29) i need to retrieve only Name-4 because ALL Expiry date from Table B are < 2018-06-29
Table A
ID | Name |
-------------
1 | Name-1
2 | Name-2
3 | Name-3
4 | Name-4
5 | Name-5
6 | Name-6
7 | Name-7
Table B
ID | A_ID | Expiry
-----------------------
1 | 1 | 2018-06-29
2 | 2 | 2018-07-29
3 | 2 | 2018-06-29
4 | 3 | 2018-07-29
5 | 3 | 2018-04-29
6 | 4 | 2018-05-29
7 | 4 | 2018-04-29
8 | 6 | 2018-09-29
9 | 6 | 2018-10-29
You are correct that you need both the GROUP BY and the HAVING clauses. Since you require that all expiry dates for a matching A_ID are less than a given date, you must check the MAX() expiry for that grouping.
SELECT ta.* FROM tableA ta JOIN tableB tb ON ta.ID = tb.A_ID
GROUP BY ta.id
HAVING MAX(Expiry) < '2018-06-20';
DEMO

Relational Table DB

I have two tables:
Users Table:
ID | Name | UserGroupID |
1 | John | 2
2 | Sam | 11
3 | Kiddo | 2
4 | Sony | 3
5 | Jabeen | 1
UsersMachine Table:
ID | MachineID | EmpID
1 | 1 | 1
2 | 2 | 1
3 | 1 | 2
4 | 2 | 2
5 | 2 | 4
6 | 3 | 5
i m looking at single sql to repeat all Users by filtering
FROM UserMachine WHERE MachineID = 2 ALSO FROM Users WHERE UsersGroupID IN (2,11) with these conditions
I m looking at following reasults:
MachineID | UsersName | UsersGroupID
2 | John | 2
2 | Sam | 11
Check out joins. They allow us to associate data from two different tables in a single query:
SELECT um.MachineId, users.Name, users.UsersGroupID FROM UsersMachine um
INNER JOIN Users users ON users.id = um.EmpID
WHERE um.MachineID = 2 AND users.UsersGroupID IN (2,11)
This is probably the best post (visually) I have seen that help me with joins:
http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/

divide column values (numbers) based on group by

First of all I am not really good with MySQL whatever experience I have I am putting it to make this query
In my query the main problem is with
left join subdealers as subdealer
ON
(
employees.Salesman1Number = subdealer.employee_number
OR employees.Salesman2Number = subdealer.employee_number
OR employees.Salesman3Number = subdealer.employee_number
)
I am trying to get the FrontGross, BackGross etc grouped by subdealer.group_name the problem is Saleman1Number & Salesman2Number might belong to same group_name and in the query below it counts them as two different Salesmen while what I want them to count as one in case the Salesman1Number, Saleman2Number and Salesman2Number belongs to same subdealer.group_name
For example: Salesman1Number belongs to group_name Fleet and Salesman2Number also belongs to Fleet
They both contributed to sell a single car. Now they both have half credit of what they sold and that credit goes to group_name Fleet as one, half from Salesman1Number and half from Salesman2Number
currently the query I wrote doesn't divide them in half depending on their group_name but count it as one from Salesman1Number
and one from Salesman2Number
SELECT count(core_leads.core_id) as leads,
count(new.id) as new,
count(used.id) as used,
IFNULL(SUM(profit.FrontGross) + SUM(finance.HoldbackAmount), 0) as FrontGross,
IFNULL(SUM(profit.BackGross) + SUM(profit.FinanceReserve), 0) as BackGross,
IFNULL(SUM(profit.TotalProfit), 0) as TotalProfit,
IFNULL(SUM(finance.HoldbackAmount), 0) as HoldbackAmount,
IFNULL(SUM(finance.Holdcheck), 0) as Holdcheck,
IFNULL(subdealer.group_name, 'Others') as group_name
from core_leads
inner join
(
select * from closed_deals
right join
(
select ContractDate, id as infoId, closed_deal_id
from closed_deal_infos
) as info
ON closed_deals.id = info.closed_deal_id
AND DATE(info.ContractDate) BETWEEN '2014-01-01' AND '2017-01-01'
) as closed
ON core_leads.core_id = closed.core_lead_id
AND core_leads.type != 'Unwind'
AND core_leads.type != 'Canceled'
left join closed_vehicles as used
ON closed.id = used.closed_deal_id
AND used.NewUsed = 'U'
left join closed_vehicles as new
ON closed.id = new.closed_deal_id
AND new.NewUsed = 'N'
left join closed_dealer_employees as employees
ON closed.id = employees.closed_deal_id
left join subdealers as subdealer
ON
(
employees.Salesman1Number = subdealer.employee_number
OR employees.Salesman2Number = subdealer.employee_number
OR employees.Salesman3Number = subdealer.employee_number
)
AND
(
subdealer.group_name = 'Fleet'
OR subdealer.group_name = 'Internet'
OR subdealer.group_name = 'Sales'
)
left join closed_profit as profit
ON closed.id = profit.closed_deal_id
left join closed_finance as finance
ON closed.id = finance.closed_deal_id
group by subdealer.group_name
This results this
While in the Fleet dept column name leads should be 38 instead of 40 because it is counting two different Salesmen whom belongs to same group_name as two
Let me know if I was not clear enough
To simplify your example i will use only two tables.
persons:
| personId | groupId |
|----------|---------|
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
| 4 | 3 |
| 5 | 4 |
| 6 | 5 |
activities:
| actId | person1Id | person2Id | person3Id | actValue |
|-------|-----------|-----------|-----------|----------|
| 1 | 1 | 2 | 3 | 1 |
| 2 | 1 | 2 | 4 | 10 |
| 3 | 5 | (null) | (null) | 100 |
A query which matches your problem would be:
select
p.groupId, count(a.actId) numActs, sum(a.actValue) sumVals, group_concat(a.actId) as acts
from activities a
left join persons p on (
a.person1Id = p.personId or
a.person2Id = p.personId or
a.person3Id = p.personId
)
group by p.groupId;
Result:
| groupId | numActs | sumVals | acts |
|---------|---------|---------|-------|
| 1 | 2 | 11 | 1,2 |
| 2 | 3 | 12 | 1,2,1 |
| 3 | 1 | 10 | 2 |
| 4 | 1 | 100 | 3 |
For the group with groupId=2 we have counted three activities (1,2,1). The Activity with actId=1 is counted twice because there are two persons from same group. To prevent that, we can define that a row for person2 should not be counted (should be filtered out) if person1 is from same group. And a row for person3 should not be counted if person1 or person 2 is from the same group. This can be done in the WHERE clause with dependent selects:
select
p.groupId, count(a.actId) numActs, sum(a.actValue) sumVals, group_concat(a.actId) as acts
from activities a
left join persons p on (
a.person1Id = p.personId or
a.person2Id = p.personId or
a.person3Id = p.personId
)
where (p.personId = a.person1Id
) or (
p.personId = a.person2Id and
p.groupId not in (select groupId from persons where personId = a.person1Id)
) or (
p.personId = a.person3Id and
p.groupId not in (select groupId from persons where personId in (a.person1Id, a.person2Id))
)
group by p.groupId;
Result:
| groupId | numActs | sumVals | acts |
|---------|---------|---------|------|
| 1 | 2 | 11 | 1,2 |
| 2 | 2 | 11 | 1,2 |
| 3 | 1 | 10 | 2 |
| 4 | 1 | 100 | 3 |
http://sqlfiddle.com/#!9/604a5/1
Note: If possible - you should consider to normalize your tables.

mysql query that outputs a table of data showing count

I have researched this and have not found the answer, so I thought someone here could shed some light. I'm trying to create a table of data returned showing the number of games picked for each user grouped by week numbers.
Database structure:
id | user | team | week_number
----+---------+-----------+-------------
1 | john | eagles | 1
2 | john | saints | 1
3 | harry | patriots | 1
4 | frank | cowboys | 1
5 | john | falcons | 2
6 | frank | cardinals| 2
Desired output:
week_number | frank | harry | john
------------+-------+-------+-------
1 | 1 | 1 | 2
2 | 1 | 0 | 1
I'll be using PHP to display the output.
The alternative to your desired output could be:
WEEK_NUMBER USER GAMES
1 frank 1
1 harry 1
1 john 2
2 frank 1
2 john 1
If this output could work for you, then you can run the following query:
select week_number,user,count(team) as games from table
group by week_number,user;
After banging my head in the wall, I got enlightenment and got the query finally. ;)
You could run this to achieve your desired output:
SELECT T.week_number,
IFNULL(SUM((CASE WHEN T.user = 'frank' THEN T.games END)),0) frank,
IFNULL(SUM((CASE WHEN T.user = 'harry' THEN T.games END)),0) harry,
IFNULL(SUM((CASE WHEN T.user = 'john' THEN T.games END)),0) john
FROM (select week_number,user,count(team) as games from table_name group by week_number,user) as T
GROUP BY week_number
DEMO

Filter fields from 1/n table using clause on multiple columns

ok, first of all sorry for the title, but I could not work out a better one :(
This is the problem:
I have two tables, properties and properties_rooms, linked each other by the propery ID.
properties table:
+---------------+------------+
| id_properties | pr_title |
+---------------+------------+
| 1 | test |
| 2 | dummy |
+---------------+------------+
properties_rooms table:
+---------------+-------------------+--------------+----------+
| id_prop_rooms | pro_id_properties | pro_id_rooms | pro_size |
+---------------+-------------------+--------------+----------+
| 1 | 1 | 4 | 5.00 |
| 2 | 1 | 18 | 17.00 |
| 3 | 2 | 6 | 12.00 |
| 4 | 2 | 24 | 11.00 |
| 5 | 1 | 4 | 10.00 |
| 6 | 1 | 6 | 10.00 |
| 7 | 1 | 6 | 12.00 |
+---------------+-------------------+--------------+----------+
I'm working on an advanced search, where users can search for a property that has more than a rooms of the same type (ie two bedrooms, 3 bathrooms and so on).
Sadly, I find myself stuck on this, since I can't "filter" the same dataset with multiple clause; if i have to filter only one there will be no problems, since I can use an HAVING clause.
I worked out this select:
SELECT id_properties, pro_id_rooms, COUNT(*) as total,
IF ((pro_id_rooms = 4 AND COUNT(*) >= 2) OR (pro_id_rooms = 6 AND COUNT(*) >= 2), 1, 0) as flag
FROM `properties`
INNER JOIN properties_rooms ON id_properties = pro_id_properties
WHERE id_properties IN (4,10)
GROUP BY id_properties, pro_id_rooms
ORDER BY id_properties
Inside the IN clause there are the properties that I know they have at least one of requested rooms. They came from a previous query since I have to work with GROUP BY and HAVING.
The IF part inside the select is built at run-time, since I get the information from the request.
This is the result:
+---------------+--------------+-------+------+
| id_properties | pro_id_rooms | total | flag |
+---------------+--------------+-------+------+
| 1 | 4 | 2 | 1 |
| 1 | 6 | 2 | 1 |
| 1 | 18 | 1 | 0 |
| 2 | 6 | 1 | 0 |
| 2 | 24 | 1 | 0 |
+---------------+--------------+-------+------+
I think it could work, I only need to add an HAVING flag > 0 and I'm done.
My question is, is there anything better?
Tables aren't very large: properties one could be something like 1k, rooms one about 10k.
I'm afraid that if the user puts too much rooms, the query would become an enormous IF statement...
SELECT id_properties, SUM(pro_id_rooms = 4) AS bedrooms, SUM(pro_id_rooms = 6) AS bathrooms
FROM `properties`
INNER JOIN properties_rooms ON id_properties = pro_id_properties
WHERE id_properties IN (4,10)
GROUP BY id_properties
HAVING bedrooms >= 3 AND bathrooms >= 2
Changes
SUM(pro_id_rooms = 4) AS bedrooms, SUM(pro_id_rooms = 6) AS bathrooms
For each checkbox the user has selected, you need a SUM(pro_id_rooms = x) AS nrofx in your WHERE.
HAVING bedrooms >= 3 AND bathrooms >= 2
This is where you check the number of a particular room.

Categories