I use mySQL and I have a members table with a BLOB 'contacts' field containing a comma separated list of other member's IDs:
TABLE members:
id_member = 1
firstname = 'John'
contacts (BLOB) = '4,6,7,2,5'
I want to retrieve all the first names in the 'contacts' list of an individual, with a single query. I tried the following:
SELECT firstname from members WHERE id_member IN ( SELECT contacts FROM members WHERE id_member = 1 );
It returns only one row, but when I try:
SELECT firstname from members WHERE id_member IN ( 4,6,7,2,5 );
It returns all the first names from the list. I can use two queries to achieve this, but I thought I'd double check if there's a way to make it work with one simple, elegant query.
Thanks for reading, any help appreciated.
Jul
That seems like a very poor table design. Is it possible to change it?
If you can't change the design then you can handle comma separated values in MySQL by using FIND_IN_SET but it won't be able to use indexes efficiently:
SELECT firstname
FROM members
WHERE FIND_IN_SET(id_member, (SELECT contacts FROM members WHERE id_member = 1))
But rather than going this route, I'd strongly recommend that if possible you normalize your database. Consider using a join table instead of a comma separated list. Then you can find the entries you need by using joins and the search will be able to use an index.
If you're using a serialized BLOB type column to store these values then you're not going to be able to do what you want. A more SQL friendly approach is to create a relationship table that can be used as part of a JOIN operation, such as a member_contacts table that has an association between one id_member value and some other.
Expanding your comma separated list into individual records is a pretty simple mechanical process.
Can you change this DB structure? The contacts field really should be a related table rather than a column. Assuming a contacts table with this structure:
id_contact
id_member
Then you would use EXISTS instead:
SELECT firstname from members m WHERE EXISTS (SELECT 1 FROM contacts c WHERE c.id_contact = m.id_member );
Related
I read the previous posts but I couldn't find one that answered my question.
What would be the name of the table that is made by joining two tables? The reason why I need the name is because I would like to change the column name of the new table using the ALTER TABLE (Table name) RENAME COLUMN (A) to (B). If there is no specified name, how can I name the new table?
ex
SELECT
client_id
,last_name
FROM INDIVIDUAL_CLIENT
UNION ALL
SELECT
client_id
,bus_name
FROM BUSINESS_CLIENT;
I would like to rename the column to last_name/bus_name instead of last_name
In the case of a query what temporal table a query might create internally is not relevant, because you a making a query and getting data back, it doesn't stay in the database as a table, there is no such table. Unless we make it.
if You want TSQL to change a column name it would affect your union query and I base my answer on Your
'I would like to rename the column to last_name/bus_name instead of last_name'
And think this is what you're looking for. Please correct me if it isn't.
In generic SQL what we're doing is putting a label on both projections that are to be displayed in the same column
SELECT
client_id
,last_name [last_name/ bus_name]
FROM INDIVIDUAL_CLIENT
UNION ALL
SELECT
client_id
,bus_name [last_name/ bus_name]
FROM BUSINESS_CLIENT;
update, in MySQL notation uses AS and quotes instead of angle brackets
SELECT
client_id
,last_name as "last_name/ bus_name"
FROM INDIVIDUAL_CLIENT
UNION ALL
SELECT
client_id
,bus_name as "last_name/ bus_name"
FROM BUSINESS_CLIENT;
I have a SQL Db that I am trying to query, consisting of three tables - Members, Bookings, and Facilities (country club stuff)
There is a memid column associated with each member, for which I have a first and a last name, and also who recommended them, recommendedby. Recommendedby is utilizing this memid, and I need to replace the number representing memid in recommendedby with The actual name of the person who recommended them. Any idea how I'd do this?
Here's a screenshot of the database:
Screenshot of Database
As you can see, the first/surname columns are the names of the people, and each one of them is represented by a memid, and then that same memid is used to identify who recommended them, and again I need to replace those numbers in recommendedby with the actual name of the recommending member.
That's a self-join:
select m.*,
r.surname recommendedby_surname,
r.firstname recommendedby_firstname
from members m
inner join members r on r.memid = r.recommendedby
I have two tables in MySql DB named as 'Patients' and 'Country'.
Patient table contains
'name','dob',postcode','address', 'country_id' etc.
Country table has
'id' and 'country_name' columns.
Now, I want the user to enter anything from a patient's name, postcode or country and get the required patient's result/data.
To achieve this, one way that I can think of is to perform the query using joins.
The other way, I wanted to ask was will it be a good approach to store the search variables i.e name, postcode and country in a column with full-text type in a way like this 'name_postcode_country' and when a user enters the search variable I perform the full-text search on the newly created column.
Or there's any other better approach that I should be considering.
It's not a good idea to hold all those info at a single column, you may use such a combination with a SELECT that JOINs the mentioned tables :
select p.name, p.dob, p.postcode, p.address,
c.country_name
from Patients p
inner join Country c
on ( p.country_id = c.id )
where ( upper(name) like upper('%my_name_string%') )
or ( upper(postcode) like upper('%my_postcode_string%') )
or ( upper(country) like upper('%my_country_string%') );
you need to use upper or lower pseudocolumns against case-sensitivity problems.
This question already has an answer here:
How can I use FIND_IN_SET within a JOINED table?
(1 answer)
Closed 5 years ago.
Got 2 tables - contacts and messages:
contact_id | contact_email
1 | some#mail.com
2 | other#mail.com
3 | no#nono.com
message_id | message_recipients
1 | 1,2,3
2 | 3
message_recipients field contains ID(s) of contact(s) message was assigned to. Each message can have one or more IDs assigned, so they are separated by , symbol.
I need to show all contacts, and count of messages are assigned to each contact. Since message_recipients field may contain multiple IDs, I can't run a query like SELECT * FROM contacts, messages WHERE contacts.contact_id=messages.message_recipients because it won't work properly.
If I run SELECT * FROM contacts FULL JOIN messages, it returns many duplicated rows from contacts table. Sure thing, I can run SELECT * FROM contacts FULL JOIN messages GROUP BY contact_id, but this one returns only 1st message from messages table.
I know that in order to count how many messages each contact has assigned to, I will probably need to explode message_recipients field from each row into array and use code like if (in_array($contact_id, $message_recipients_array)) {$total++;} or similar. Now my main concern is how to all I need by writing as simple query as possible.
Fix your table structure. Do not store multiple values in one cell. See Normalization
For now, you can use FIND_IN_SET:
select c.contact_id,
c.contact_email,
count(*) no_of_messages
from messages m
join contacts c on find_in_set(c.contact_id, m.message_recipients) > 0
group by c.contact_id,
c.contact_email
But this will be slow as it can't use any index on the contact_id or message_recipients.
To actually fix the issues, don't include recipient_id in the messages table.
You should have stored single recipient in one row in a separate mapping table with many to many relation with (maybe) the following structure.
messages_recipients (
id int PK,
message_id int FK referring message(message_id),
message_recipient_id int FK referring contacts(contact_id)
)
Then all you had to do was:
select c.contact_id,
c.contact_email,
count(*) no_of_messages
from messages_recipients m
join contacts c on c.contact_id = m.message_recipient_id
group by c.contact_id,
c.contact_email
This query is Sargable and will be faster.
Fix your data structure! Storing ids in strings is a really bad idea. Why?
Numbers should be stored as numbers not strings.
SQL does not offer very good string functions.
Foreign key constraints should be properly expressed.
The query optimizer cannot use indexes or partitions.
SQL has a great method for storing lists: it is called a "table".
Sometimes, we are stuck with other people's really, really bad design decisions. MySQL does offer a method for doing what you want, find_in_set(). This is a hack to get around the short-comings of a bad data layout:
select . . .
from contacts c join
messages m
on find_in_set(c.contact_id, m.message_recipients) > 0
I have a table with a bunch of orders... one of the columns is order_status. The data in that column ranges from 1 to 5. Each number relates to a name, which is stored in another table that relates that number to the respective name.
SELECT order_id , order_status FROM tablename1
The above would just return the numbers 1,2,3,4,5 for order status. How can i query within the query on the fly to replace these numbers with their respective names.
Also, what's the term used to describe this. I'd Google it if i knew what the appropriate term was.
Each number relates to a name, which is stored in another table that
relates that number to the respective name.
JOIN it with the other table:
SELECT
t.order_id,
s.StatusName
FROM tablename1 AS t
INNER JOIN the statusesTable AS s ON t.order_status = s.status_id;