SQL - How can i get the last two characters from a column? - mysql

I have three tables.
users - user_info - districts
And I built a Inner join to get the user_id and the user_info.
Select * from users a inner join user_info b on a.id = b.user_id
But i have a column called location, inside the user_info, which returns the ID from a specific location. Just like this:
00;11
And to get the location, I have to Inner Join the user_info table, to another table called districts, because the two last characters got the ID from the district.
Thats why I would like to Inner Join all three tables, like this:
Select * from users a inner join user_info b on a.id = b.user_id inner join districts c on b.location = c.District_id
The problem is that, i want to get only the two last characters from the Location column. But i'm getting
00;11 //I would like to only get the 11
I will output everything later, using Json, and I would like to get the User info, and his location.
Is it possible to "substring" a column in SQL?
Thanks.

You could use SUBSTRING_INDEX in MySQL to get the string after the semi-colon
SELECT SUBSTRING_INDEX('00;11', ';', 2);
Or in your case:
Select SUBSTRING_INDEX(Location, ';', 2),* from users a inner join user_info b on a.id = b.user_id inner join districts c on b.location = c.District_id
Alternatively you can take the last two characters of your string using RIGHT
SELECT RIGHT('00;11', 2);

Yes, it is. See: MySQL String Functions
mysql> SELECT RIGHT('foobarbar', 4);
-> 'rbar'
For further information, please see:
SUBSTR
RIGHT

Related

mysql leftjoin by max autoincrement id?

A) users
B) subscribtion
C) package information
I've table where B is a link between A and C , the query selected from A where B has row id for A and join C by B id .
Full example :
SELECT a.*,c.packageTitle
FROM users AS a
LEFT JOIN subscribe AS b ON (b.userid = a.userid)
LEFT JOIN package AS c ON (b.packageid = c.packageid)
my problem if user has multi subscription in C, i cannot get latest subscription row in loop query, i also used MAX(c.packageid) inside SELECT failed also .
Goal : get latest record in B assigned by A id .
any advice is very much appreciated
I don't think you were far off by trying to use MAX() to obtain the record with the latest package ID (which assumes that this ID is an increasing auto-increment column). In my answer below, the subquery identifies the latest package ID for each user record, using a GROUP BY. This subquery is then used to filter the correct records from your original query.
SELECT a.userid, b.*
FROM users AS a
LEFT JOIN subscribe AS b
ON b.userid = a.userid
LEFT JOIN package AS c
ON b.packageid = c.packageid
INNER JOIN
(
SELECT a.userid, MAX(c.packageTitle) AS maxPackageTitle
FROM users AS a
LEFT JOIN subscribe AS b
ON b.userid = a.userid
LEFT JOIN package AS c
ON b.packageid = c.packageid
GROUP BY a.userid
) t
ON a.userid = t.userid AND c.packageTitle = t.maxPackageTitle
As a note, this query would greatly benefit from something called a Common Table Expression (CTE), which is available in other RBDMS such as SQL Server and Oracle. A CTE would make the query much less repetitive and more readable.
This should be simple enough. In Mysql you just as you said put a max on the select along with a group by. So it would look something like:
SELECT username, id_info, ...
FROM
(
SELECT a.username, a.id_info, c.packageTitle, MAX(package_id)
FROM users AS a
LEFT JOIN subscribe AS b
ON b.userid = a.userid
LEFT JOIN package AS c
ON b.packageid = c.packageid
GROUP BY a.username, a.id_info, c.packageTitle
)
Remember to list all columns in the select which are also being grouped, except the one on which you are taking the max, or the query will fail.

Get multiple value in single row using join

I want to get multiple values in a single row which matches with primary table. Below are the example tables:
members:
- id
- name
- status
address:
- id
- ref_id(member id)
- address1
- state
contacts:
- id
- ref_id(member id)
- phone
- email
mem_cc
- id
- ref_id(member id)
- category_id
- coverage_id
I'm using below query to create view to get all the records in single view so I can query that view to display a list page:
SELECT a.id, a.name, a.status, b.address1, b.state, c.phone, d.category_id, d.coverage_id
FROM members a LEFT JOIN address b
ON a.id = b.ref_id
LEFT JOIN contacts c
ON a.id = c.ref_id
LEFT JOIN mem_cc d
ON a.id = d.ref_id
Now case like Member A is subscribed with 3 coverages or 3 categories then it'll show me Member A's record three times, I want to get Member A record in table single time with covering all categories and coverages in that single row. Question is how to do that?
I believe you need function "group_concat" when selecting the category:
select a.id,a.name,a.status,b.address1,b.state,c.phone,
group_concat(d.category_id, d.coverage_id)
from members a left join address b on a.id = b.ref_id
left join contacts c on a.id = c.ref_id and left join mem_cc d on a.id = d.ref_id
group by a.id
As DMorillo already said you will have to use grouping. In this way you will get one record for the user and in the different columns you can then group the results as necessary.
If you were thinking of extra columns popping up based on your joins then I don't think this is possible. See if the query below works for your case.
SELECT a.id,
a.name,
a.status,
-- This group_concat will produce something like "5th street - Alabama"
-- separated with newlines
-- Check for NULL values since you are using left joins
GROUP_CONCAT(IFNULL(CONCAT(b.address1, ' - ', b.state), ''))
DELIMITER '\n') AS address,
-- Same goes for phone numbers. Default delimiter is comma.
GROUP_CONCAT(IFNULL(c.phone, '') DELIMITER ','),
-- Now you can group your categories.
GROUP_CONCAT(IFNULL(CONCAT(d.category_id,' ', JOINEDCATEGORYNAME), '') AS category,
GROUP_CONCAT(IFNULL(CONCAT(d.coverage_id,' ', JOINEDCOVERAGENAME), '') AS coverage
FROM members a
LEFT JOIN address b ON a.id = b.ref_id
LEFT JOIN contacts c ON a.id = c.ref_id
LEFT JOIN mem_cc d ON a.id = d.ref_id
-- Here probably your inner joins to categories table and coverage table
GROUP BY a.id

Select Query in MySQL for multiple tables

I m working in MySQL and have to write a select query.
I have related data in four tables. Now, the parent table may have data whose child data may not be present in lower tables.
I want to write a single query to get data from all four tables, irrespective of situation that data is present in child tables or not.
I have tried to write nested select and joins as below, but m not getting the data.
select * from property p where p.Re_ID in
(select Re_id from entry e where e.Re_ID in
(select Re_id from category c where c.Re_ID in
(select id from re)))
Please help me how to get data from all 4 tables.
If cir_registry is the master, you can select from that and LEFT JOIN the other tables in the order they're distant from cir_registry;
SELECT r.ID rId, r.Description rDescription, c.ID cId ...
...
p.Data_Type pDataType
FROM cir_registry r
LEFT JOIN cir_category c ON c.Registry_ID = r.ID
LEFT JOIN cir_entry e ON e.Category_ID = c.ID
LEFT JOIN cir_property p ON p.Entry_IDInSource = e.IDInSource
You should also alias the columns as above, otherwise, for example, p.ID and c.ID will both show up in the result set as ID, and you'll only be able to access one of them.
You might need UNION? Something like:
Select * FROM cir_registry
Union
Select * FROM cir_entry
Union
Select * FROM cir_property
Check the official doc here: http://dev.mysql.com/doc/refman/5.0/en/union.html

MySQL join two columns on a single column

I have 2 tables:
table_name: user_tracking
With columns: id, bill_no, container_type, origin_id, destination_id
table_name: sea_ports
With columns: id, bill_no, port_name
I want to write a single query to get the origin port_name and the destination port_name.
my query is :
select a.container_type,
b.port_name as origin_port
from user_tracking a
left join sea_ports b
on a.bill_no = b.bill_no
where a.bill_number = '$bill_no'
How do I join the two columns origin_id and destination_id on the same field id from the table sea_ports to get two different outputs?
You need to join the table sea_ports twice so you can get the port_name for each origin and destination. And One more thing, I guess, you need need to use INNER JOIN rather than LEFT JOIN because there will always be destination and origin right? :D
SELECT a.ID,
a.bill_no,
a.container_type,
b.port_name AS Origin_name,
c.port_name AS Destination_name
FROM user_tracking a
INNER JOIN sea_ports b
ON a.origin_id = b.id
INNER JOIN sea_ports c
ON a.destination_id = c.id
WHERE a.bill_number = '$bill_no'
As a sidenote, the query is vulnerable with SQL Injection if the value(s) came from the outside. Please take a look at the article below to learn how to prevent from it. By using PreparedStatements you can get rid of using single quotes around values.
How to prevent SQL injection in PHP?

How do you do a mysql join where the join may come from one or another table

This is the query that I am using to match up a members name to an id.
SELECT eve_member_list.`characterID` ,eve_member_list.`name`
FROM `eve_mining_op_members`
INNER JOIN eve_member_list ON eve_mining_op_members.characterID = eve_member_list.characterID
WHERE op_id = '20110821105414-741653460';
My issue is that I have two different member lists, one lists are members that belong to our group and the second list is a list of members that do not belong to our group.
How do i write this query so that if a member is not found in the eve_member_list table it will look in the eve_nonmember_member_list table to match the eve_mining_op_members.characterID to the charName
I apologize in advance if the question is hard to read as I am not quite sure how to properly ask what it is that I am looking for.
Change your INNER JOIN to a LEFT JOIN and join with both the tables. Use IFNULL to select the name if it appears in the first table, but if it is NULL (because no match was found) then it will use the value found from the second table.
SELECT
characterID,
IFNULL(eve_member_list.name, eve_nonmember_member_list.charName) AS name
FROM eve_mining_op_members
LEFT JOIN eve_member_list USING (characterID)
LEFT JOIN eve_nonmember_member_list USING (characterID)
WHERE op_id = '20110821105414-741653460';
If you have control of the database design you should also consider if it is possible to redesign your database so that both members and non-members are stored in the same table. You could for example use a boolean to specify whether or not they are members. Or you could create a person table and have information that is only relevant to members stored in a separate memberinfo table with an nullable foreign key from the person table to the memberinfo table. This will make queries relating to both members and non-members easier to write and perform better.
You could try a left join on both tables, and then selecting the non-null results from the resulting query -
select * from
(select * from
eve_mining_op_members as x
left join eve_member_list as y1 on x.characterID = y1.characterID
left join eve_member_list2 as y2 on x.characterID = y2.characterID) as t
where t.name is not null
Or, you could try the same thing with a union and using inner join (assuming joined tables are the same):
select * from
(select * from eve_mining_op_members as x
inner join eve_member_list as y1 on x.characterID = y1.characterID
UNION
select * from eve_mining_op_members as x
inner join eve_member_list2 as y2 on x.characterID = y2.characterID) as t
You can throw in your op_id condition where you see fit (sorry, I didn't really understand where it came from). Good luck!
You have several options but by
using a UNION between the eve_member_list and eve_nonmember_member_list table
and JOIN the results of this UNION with your original eve_mining_op_members table
you will get your required results.
SQL Statement
SELECT lst.`characterID`
, lst.`name`
FROM `eve_mining_op_members` AS m
INNER JOIN (
SELECT characterID
, name
FROM eve_member_list
UNION ALL
SELECT characterID
, name
FROM eve_nonmember_member_list
) AS lst ON lst.characterID = m.characterID
WHERE op_id = '20110821105414-741653460';