mysql - select email from xyz where email="%gmail.com" - php

Is there a way I can select from the database the entries with certain data? I got a lot of email addresses in the database but I want to select only from one domain. Is it even possible?

Sure - just use the LIKE operator.
SELECT email FROM Persons
WHERE email LIKE '%gmail.com'

You are not advisable to do a wildcard search.
This is because mysql not able to use index to fasten the select query.
Especially you mention you have lots of email in the database.
Alternatively, you can use an additional field, as hostname to store just the hostname only.
And of course build an index to it.
If you need to search for email with gmail.com,
then you can do straight string comparison
SELECT email FROM Persons
WHERE hostname='gmail.com';
As the straight string comparison is the good mate to mysql index, your query will be optimized.

As ajreal points out, MySQL can't use indexes to optimise a LIKE query in the general case. However in the specific case of a trailing wildcard where the only % is at the very end of the pattern (effectively a "starts with" query), the optimiser can do a good job of speeding up the query using an index.
Therefore, if you were to add an additional indexed column storing the email address in reverse, you could efficiently query for
SELECT email FROM xyz WHERE reverse_email LIKE 'moc.liamg#%`
to find all gmail addresses, or LIKE 'ku.% for all addresses under uk domains, etc. You can have the database keep this column up to date for you using triggers, so it doesn't affect your existing update code
CREATE TRIGGER emailinsert BEFORE INSERT ON xyz
FOR EACH ROW SET NEW.reverse_email = REVERSE(NEW.email);
CREATE TRIGGER emailupdate BEFORE UPDATE ON xyz
FOR EACH ROW SET NEW.reverse_email = REVERSE(NEW.email);

You need to use LIKE MYSQL CLAUSE
SELECT * FROM email_table WHERE email LIKE "%gmail.com"

Related

Multiple Long Concurrent MySQL Queries

I have a MySQL database that has around 600,000 records in the largest table. The other tables are fairly small in comparison. The data is somewhat normalized but there is some duplication because I'm using it for personal use and when I tried fully normalizing it, I found the queries to be unnecessarily complex and slow from all of the joins. I am using PHP to execute the queries.
Now, for example, say that the 600,000 record table contains email addresses. Imagine I have about 10 applications/clients that need to retrieve an email address from this table based on conditions and joins and no two clients should get the same email address. So, I created a query that selects an email address and then another query that uses the selected email address to update a flag field to mark the email address as "in use" and so another client cannot take the same email address. The problem is the query to select the email address takes about 25 seconds to execute and when two clients execute at the same time, they receive the same email address. The speed is not an issue because the clients will only be executing this query once every few hours but I need the clients to get unique email addresses.
I'm kind of new to MySQL so I don't know if selecting the field and then setting a flag is the proper way to go about this. Is there a way to set the flag before I select the field? Also, I don't know much about transactions but could this be solved using them?
Thanks!
START TRANSACTION;
SELECT email FROM myemails WHERE flag = 0 LIMIT 1 FOR UPDATE;
UPDATE myemails SET flag = 1 WHERE email = '$email';
COMMIT;
Another possible approach is to generate a unique flag in php and update first i.e.
$flag = uniqid();
UPDATE myemails SET flag = '$flag' WHERE flag IS NULL LIMIT 1;
SELECT email FROM myemails WHERE flag = '$flag';

How to look up values from a different table?

Currently, I have a log file of messages in one table in a MySQL database. Among some other stuff, it contains the sender id, and the message itself. I want to make a way to display the log on a website.
I have a separate table that contains the sender ids and the name of the person (which is what I actually want to display).
Are there any better ways than simply running another query? While that would work, that's pretty expensive as it requires a new query for every entry. Ideally, I'd like something that would map the id --> name in an array, but I can only find things that will put everything from one row into an array (aka, horizontally), but I need entries "vertically".
I'm using PHP by the way...
Thanks!
Kevin
Learn about JOIN statements. This is exactly what you need.
I believe you are looking for something like this:
SELECT `name`, `message` FROM `msgtable` INNER JOIN `sendertable` USING(`sender_id`)

Auto-creating tables or rows with populated data in mySQL

I'm looking to create a basic IP management solution using a web front end with PHP and MySQL. I am not too familiar with PHP or MySQL but I would like to know if it would be possible to do the following:
When a user inserts a new subnet range into the database (e.g 192.168.1.0/24) using a HTML form, would it be possible for that to trigger another create table (e.g. ip_addresses) that would auto-populate the table with the subnet range (e.g. 192.168.1.1, 1.2, 1.3 and so on).
Apologies if I'm being too vague - thanks
Though it would be possible to do what you are asking, I would advise against it. In MySQL, it is common to store IP addresses as long integers, rather than as their string representation as a dotted quad. MySQL provides two functions, INET_ATON() and its counterpart INET_NTOA() to convert IP addresses into long integers.
The structure I would recommend would be to store the starting and ending integer representation of the subnets. That way, it becomes possible, if necessary to query for addresses residing between the endpoints. Also it allows you to store incomplete subnets.
From MySQL docs:
mysql> SELECT INET_ATON('10.0.5.9');
-> 167773449
mysql> SELECT INET_NTOA(167773449);
-> '10.0.5.9'
You can query with statements like:
SELECT * ipRanges WHERE INET_ATON('192.168.1.99') BETWEEN startIpNum AND endIpNum;
You could use triggers to do that.
CREATE
TRIGGER new_range INSERT
ON ip_range FOR EACH ROW BEGIN ... END
And put your logic of managing specific IP addresses in the range inside your BEGIN ... END instead of the '...'
Have a look here: http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html - for details of how this works.

How to Concat in mysql Query

Im not even sure if this is possible (Im new to php)
Anyway, what I want to do is this:
mysql_query("SELECT * FROM user_table WHERE concat(username,'#',domain)='$username' LIMIT=1");
Ok, so the $username is an email address that is submitted by a user to search the database to check that they exist. In the user_table usernames are not stored in a single column, they are stored in several with the domain and the actual username being separate.
for example username could be bob and the domain could be website.com.au
Then when the user wants to search for that user the type in bob#website.com.au
This goes to the query above.
So, should it work or not? If not how can I make this work or what suggestions do you have for me?
As BobbyJack has mentioned, this is a slow way of locating a user record.
If you cannot store email address in a single column and place an index on that column, split the string in PHP and make your query:
SELECT * FROM user_table WHERE `username` = '$username' AND `domain` = '$domain'
You could then create a unique index combining domain + username so you wouldn't need LIMIT 1
probably worded the question slightly wrong.
Anyway this is what I have done "SELECT * FROM virtual_user WHERE concat_ws('#',username,domain)='$username'"
I no longer need to use the LIMIT=1, I probably never needed to as all results in the table are individual, so it will always only return a limit of 1 or nothing at all.
It isn't slow in my opinion, but then again Im not really sure what to compare it to. We have about 7000+ records it sorts through so yeah. Is there anyway to get it to tell you how long the query took to complete?
I would like to put both the username and domain into just a single indexed field but its for a postfix mail server and I'm not allowed or game to play with the queries it uses. Especially not on a functioning server that actually handles mail.

Using explode, split, or preg_split to store and get multiple database entries

I'm trying to figure out how and which is best for storing and getting multiple entries into and from a database. Either using explode, split, or preg_split. What I need to achieve is a user using a text field in a form to either send multiple messages to different users or sharing data with multiple users by enter their IDs like "101,102,103" and the PHP code to be smart enough to grab each ID by picking them each after the ",". I know this is asking a lot, but I need help from people more skilled in this area. I need to know how to make the PHP code grab IDs and be able to use functions with them. Like grabbing "101,102,103" from a database cell and grabbing different stored information in the database using the IDs grabbed from that one string.
How can I achieve this? Example will be very helpful.
Thanks
If I understand your question correctly, if you're dealing with comma delimited strings of ID numbers, it would probably be simplest to keep them in this format. The reason is because you could use it in your SQL statement when querying the database.
I'm assuming that you want to run a SELECT query to grab the users whose IDs have been entered, correct? You'd want to use a SELECT ... WHERE IN ... type of statement, like this:
// Get the ids the user submitted
$ids = $_POST['ids'];
// perform some sanitizing of $ids here to make sure
// you're not vulnerable to an SQL injection
$sql = "SELECT * FROM users WHERE ID IN ($ids)";
// execute your SQL statement
Alternatively, you could use explode to create an array of each individual ID, and then loop through so you could do some checking on each value to make sure it's correct, before using implode to concatenate them back together into a string that you can use in your SELECT ... WHERE IN ... statement.
Edit: Sorry, forgot to add: in terms of storing the list of user ids in the database, you could consider either storing the comma delimited list as a string against a message id, but that has drawbacks (difficult to do JOINS on other tables if you needed to). Alternatively, the better option would be to create a lookup type table, which basically consists of two columns: messageid, userid. You could then store each individual userid against the messageid e.g.
messageid | userid
1 | 1
1 | 3
1 | 5
The benefit of this approach is that you can then use this table to join other tables (maybe you have a separate message table that stores details of the message itself).
Under this method, you'd create a new entry in the message table, get the id back, then explode the userids string into its separate parts, and finally create your INSERT statement to insert the data using the individual ids and the message id. You'd need to work out other mechanisms to handle any editing of the list of userids for a message, and deletion as well.
Hope that made sense!
Well, considering the three functions you suggested :
explode() will work fine if you have a simple pattern that's always the same.
For instance, always ', ', but never ','
split() uses POSIX regex -- which are deprecated -- and should not be used anymore.
preg_split() uses a regex as pattern ; and, so, will accept more situations than explode().
Then : do not store several values in a single database column : it'll be impossible to do any kind of useful work with that !
Create a different table to store those data, with a single value per row -- having several rows corresponding to one line in the first table.
I think your problem is more with SQL than with PHP.
Technically you could store ids into a single MySQL field, in a 'set' field and query against it by using IN or FIND_IN_SET in your conditions. The lookups are actually super fast, but this is not considered best practice and creates a de-normalized database.
What is nest practice, and normalized, is to create separate relationship tables. So, using your example of messages, you would probably have a 'users' table, a 'messages' table, and a 'users_messages' table for relating messages between users. The 'messages' table would contain the message information and maybe a 'user_id' field for the original sender (since there can only be one), and the 'users_messages' table would simply contain a 'user_id' and 'message_id' field, containing rows linking messages to the various users they belong to. Then you just need to use JOIN queries to retrieve the data, so if you were retrieving a user's inbox, a query would look something like this:
SELECT
messages.*
FROM
messages
LEFT JOIN users_messages ON users_messages.message_id = messages.message_id
WHERE
users_messages.user_id = '(some user id)'

Categories