I'm trying to do return results from one table based on multiple results on another. Here's the setup:
Table A: "accounts"
id | fname | other_id
1 | test | 500
2 | test2 | 505
3 | test3 | 500
4 | test4 | 540
5 | test5 | 500
Table B: "transactions"
id | account_id |
1 | 1
2 | 4
3 | 2
4 | 1
5 | 3
6 | 2
What I'm trying to accomplish is, return all id's from transactions where account_id = the id in table A WHERE other_id = a certain value.
To do write it out manually it would look like this:
So for example if other_id = 500.
1) get records from accounts where other_id = 500 (will be multiple results, in this case, 1, 3 and 5)
2) get records from transactions where account_id = 1 OR account_id = 3 OR account_id = 5
I've tried a few different subselects but can't seem to come up with what I'm looking for.
I of course could just break this up into a loop using PHP but I'd rather use a single query for efficiency.
No subselect required, just a simple join.
select * from accounts a, transactions t where t.account_id=a.id and other_id=500
select t.id
from accounts as a
inner join transactions as t on a.id = t.account_id
where a.other_id=500
If i understand you right, you want this.
SELECT b.id
FROM accounts AS a
LEFT JOIN transactions AS b ON b.account_id = a.id
WHERE other_id = 500
Related
I am looking for a way to get groups of the GROUP_CONCAT() function in a single query, for example.
My current code
SELECT
SUBSTRING_INDEX(GROUP_CONCAT(service_info.ip_address SEPARATOR ','),',',service_plans.aggregation) AS ip_address
FROM
services
LEFT JOIN
service_info
ON
service_info.service_id = services.id
LEFT JOIN
service_plans
ON
service_plans.id = services.service_plan_id
WHERE
service_plans.id = '2'
I want to group the IP addresses by a specific number(the $group_by variable if you see in the query) but then separate by a different character such as ":" or something.
Essentially I want my output to look like:
If $group_by=2: 10.1.1.2,10.1.1.3:10.1.1.4,10.1.1.5
If $group_by=3: 10.1.1.2,10.1.1.3,10.1.1.4:10.1.1.5
Is this possible to implement into my current query?
UPDATE: table structure
Table service_plans
id | name | aggregation
-----------------------------------------
1 | Uncapped 10Mbps 20:1 | 20
2 | Uncapped 20Mbps 10:1 | 10
3 | Capped 30Mbps | 0
Table services
id | service_plan_id | description
------------------------------------
1 | 2 | Phone
2 | 2 | Laptop
3 | 2 | PC
4 | 2 | TV
5 | 2 | Test
Table service_info
id | service_id | ip_address
------------------------------
1 | 1 | 10.1.1.2
2 | 2 | 10.1.1.3
3 | 3 | 10.1.1.4
4 | 4 | 10.1.1.5
5 | 5 | 10.1.1.6
I am trying to get an array of ip_address's concatenated and separated by a comma but the in groups of however much the service_plans.aggregation value is.
If aggregation is 2, then my output should be:
10.1.1.2,10.1.1.3:10.1.1.4,10.1.1.5
As you can see they are in groups of 2 and then the next group is separated by a colon(:)
If aggregation is 3, then my output should be:
10.1.1.2,10.1.1.3,10.1.1.4:10.1.1.5
As you can see they are in groups of 3 and then the next group is separated by a colon(:) and so on
Your post is a little confusing. What would be helpful is if you posted sample data, and then posted what you want your query to return. I'll give you an answer to what I think you're asking, based on the subject of your post.
ServicePlanIPs
service_plan_id | ip_address
-------------------------------
1 | 192.168.70.1
1 | 192.168.70.2
1 | 192.168.70.3
2 | 192.168.70.4
2 | 192.168.70.5
2 | 192.168.70.6
If you run this query against ServicePlanIPs:
SELECT service_plan_id, GROUP_CONCAT(ip_address) as ip_addresses
FROM ServicePlanIPs
GROUP BY service_plan_id
You will get:
service_plan_id | ip_addresses
-------------------------------
1 | 192.168.70.1, 192.168.70.2, 192.168.70.3
2 | 192.168.70.4, 192.168.70.5, 192.168.70.6
I don't guarantee this will run out of the box, but it should get you on the right track. Hope it helps. Note - if you're using a version of mysql which supports window functions, you can do something similar to the below and use the natively supported RANK function instead of doing it manually with variables.
SET #curRank := 0;
SET #concatIps := '';
SELECT
sp.id,
#curRank := #curRank + 1 AS rank,
IF(MOD(#curRank, (SELECT aggregation FROM service_plans WHERE id = {service_plan_id}) = 0, #concatIps := CONCAT(#concatIps, ':', s.ip_address), #concatIps := CONCAT(#concatIps, ',', s.ip_address))
FROM service_plans sp
JOIN services s
ON sp.id = s.service_plan_id
JOIN service_info si
ON si.service_id = s.id
WHERE sp.id = {service_plan_id}
ORDER BY service_info_id
[TABLE 1]
+---------+---------+------------------+
| post_id | user_id | description |
+---------+---------+------------------+
| 1 | 1 | Sample post 1 |
| 2 | 1 | Sample post 2 |
| 3 | 2 | Sample post 3 |
| 4 | 2 | Sample post 4 |
| 5 | 3 | Sample post 5 |
+---------+---------+------------------+
[TABLE 2]
+---------+---------+---------+
| id | user_id | post_id |
+---------+---------+---------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
+---------+---------+---------+
When the USER_ID 1 in TABLE 1 already existed in TABLE 2 with its respected POST_ID, it should not be part of return select query. Instead, it would return POST_ID 2,3,4,5 in TABLE 1.
When the USER_ID 2 in TABLE 1 already existed in TABLE 2 with its respected POST_ID, the expected return select query would be POST_ID 1,3,4,5 in TABLE 1 as well as the other id's.
Thanks in advance guys! :)
Looks like an anti join pattern could achieve the specified result.
SELECT t.post_id
, t.user_id
, t.description
FROM `[Table 1]` t
LEFT
JOIN `[Table 2]` u
ON u.post_id = t.post_id
AND u.user_id = ?
WHERE u.post_id IS NULL
ORDER BY t.post_id
The ? is the placeholder character for specifying a userid.
This essentially says return all rows from Table 1 along with matching rows from Table 2, but (here's the trick) the WHERE clause says to exclude all rows that found a matching row in Table 2. Leaving only rows from Table 1 that don't have a match in Table 2.
The anti join takes a little bit of effort to get your brain wrapped around, but once you get it, it's an invaluable tool to keep handy in the SQL toolbelt.
There are other query patterns that will return an equivalent result, such as a NOT EXISTS (correlated subquery) or the more common NOT IN (subquery). (With the NOT IN, be careful that the subquery doesn't return any NULL values.)
EDIT
Removed the condition u.user_id = t.user_id from the join predicate. Looks like the user_id in [Table 1] is the "author" of the post. And has no relation to whether a user has "viewed" a post or not.
Base on your sample data, because USER_ID 1 in TABLE 1 already existed in TABLE 2 with its respected POST_ID, it should return POST_ID 2,3,4,5.
Query:
SELECT t1.* FROM table2 t2
RIGHT OUTER JOIN table1 t1
ON t2.user_id = t1.user_id AND t2.post_id = t1.post_id
WHERE t2.user_id IS NULL
Final Result:
post_id user_id description
2 1 Sample post 2
3 2 Sample post 3
4 2 Sample post 4
5 3 Sample post 5
Is this what you are looking for?
Need some help.
I have got 3 tables. klients, klientwithservice, service.
table klients
id | klientrnd
---------
1 | 11231231
2 | 22222222
table service
id | servicename
---------
1 | Repair laptop
2 | Repair pc
table klientwithservice
id | klientrnd | serviceid
-------------------------------
1 | 11231231 | 1
2 | 11231231 | 2
3 | 22222222 | 1
4 | 22222222 | 2
I need to output SERVICENAME instead ID.
My sql query is:
SELECT serviceid FROM klientwithservice WHERE '$pole8' = `klientrnd`
Where $pole8 = klientrnd exactly person on which page i placed.
for this you need to JOIN two table
use below query
SELECT s.servicename FROM klientwithservice as kws
JOIN service as s ON s.id = kws.serviceid
WHERE `klientrnd` = '$pole8'
Firstly your sql SELECT serviceid FROM klientwithservice WHERE '$pole8' = klientrnd is wrong.
It will return a syntax error stating the unknown column $pole8 (it's exact value) `is wrong
Second you should use join to achieve what you're after. Try this:
SELECT s.servicename FROM klientwithservice as k
JOIN service as s ON s.id = k.serviceid
WHERE k.klientrnd = '$pole8'
I have two tables.
Table1:
deviceID | PartA-present | PartB-present
------------+---------------+---------------
123 | 0 | 1
254 | 1 | 0
152 | 1 | 1
Table 2:
deviceID | PartA-Data | PartB-Data
------------+---------------+---------------
123 | 0 | 13
152 | 4 | 25
123 | 0 | 67
152 | 38 | 32
Now, the presence of partA, partB, etc are dynamic based on user settings. How can I form a query to export only those columns from table2 for which the parts are present (As indicated in table 1)?
In this case, for deviceID=123, I need to export only partB-Data from table 2
EDIT
Based on the answers I got, I think I should clarify. I have some idea of JOIN, but I cannot figure out how to get the following result.
Desired Result (for deviceID123):
deviceID | PartB-Data |
------------+---------------+
123 | 13 |
123 | 67 |
Desired Result (for deviceID 152):
deviceID | PartA-Data | PartB-Data
------------+---------------+---------------
152 | 4 | 25
152 | 38 | 32
UPDATE
What I was looking for was to get different number of columns in the output based on query, but thanks to #Alex, I realized it is not possible. In that sense, I can simply export table 2 for deviceID=xxx bcz the non relevant data is 0 anyways.
Your goal is not clear. But just as a start point try this fiddle
http://sqlfiddle.com/#!9/0bb4d/1
SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2
ON t1.deviceid = t2.deviceid
WHERE t1.deviceID = 123
AND (t1.partA OR t2.partB)
EDIT 1 it is not about your table1 fields, it is about logic
check this fiddle:
http://sqlfiddle.com/#!9/a7984/5
and this query
SELECT t1.deviceid,
IF(t1.partA=1, t2.partA, IF(t1.partB=1,t2.partB,null))
FROM table1 t1
INNER JOIN table2 t2
ON t1.deviceid = t2.deviceid
WHERE t1.deviceID = 123
AND (t1.partA OR t2.partB);
even if it brings expected result for deviceid=123, does it still work for deviceid=152?
EDIT 2 Hope I get your goal correctly. Check new fiddle: http://sqlfiddle.com/#!9/a7984/7
SELECT t1.deviceID,
IF(t1.partA=1, t2.partA, null),
IF(t1.partB=1, t2.partB, null)
FROM table1 t1
INNER JOIN table2 t2
ON t1.deviceid = t2.deviceid
WHERE t1.deviceID = 123
AND (t1.partA OR t2.partB);
Your query should look like this:
SELECT table2.*, table1.*
FROM table2
INNER JOIN table1 ON table1.deviceID = table2.deviceID
WHERE table2.deviceID = 123
AND (table1.PartA-present = 1 OR table1.PartB-present = 1)
This will join the two tables together and will only return rows when the a is present.
You should select all entries in table 2 where one of the parts is present and then just check using php
if ($row['PartA-present'] == 1) {
echo $row['PartA-Data'];
}
It might make more sense to simply make your table look like this though:
Table 2:
deviceID | PartA-Data | PartB-Data
------------+---------------+---------------
123 | -1 | 13
123 | -1 | 25
A -1 indicates the part isn't present. That way your queries will be faster and simpler because you'll be eliminating the join which adds time and complexity to the query.
I have tables like this
mainTable
Id | name | country
1 | John | 5
2 | Bill | 7
categoriesTable
other_table_id | category
1 | 6
1 | 12
My question is how can I say
SELECT id FROM mainTable
WHERE country=5
AND WHERE categoriesTable order_table_id=[**THE ID I JUST GOT FROM THE FIRST TABLE**] && category=6 || category=12
Then returns the number of records that match so in this case 1
Thanks!
Doesn't anyone learn how to write JOINs when they learn SQL?
SELECT m.id
FROM mainTable AS m
JOIN categoriesTable AS c ON c.other_table_id = m.id
WHERE c.category IN (6, 12)
AND m.country = 5