TheBiscuit has asked for the
wisdom of the Perl Monks concerning the following question:

I would like to reduce the number of MySQL queries executed by running a single SELECT statement then later referencing the results, preferably by a single column. Unfortunately, I'm not quite sure how and am hoping for a bit of help. The SELECT statement looks like this:

Is it possible to somehow reference a specific row by the username, to pull the email and phone values? If not, what is the best way to pull the specific values? This will be done within a foreach loop where the username is pulled from another source.

AS others already showed, it is possible to do so, but in most of the scenario's I can think of, this is not a good idea.

Unless you are guaranteed that the contents of the table will not change during the lifetime of your script, you are not going to pick up any changes to it and therefore may be working with stale data.

If the table is very big, you will download a lot of data to a variable structure in your script, of which you perhaps only use a very small part. This is wasteful of memory and will scale very badly.

Databases are made to be rather efficient to hand you back the answer to your queries. Over the aggregated lifetime of your script is likely that the database will do a better job than you can.

CountZero

A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

The point of using a placeholder is to prevent abuse of the single quote in SQL injection attacks on the database, if say "bob" where actually an $input and you are operating in an insecure environment.

I apologize for not being clear enough, but this is a Perl question. The script I am trying to modify currently runs a SELECT query with a WHERE statement multiple times within a foreach loop. I would like to run the query once and pull the necessary data from an array instead. Below is the segement of code I'm working with:

In the section noted as "***** Insert Match Here *****, I would like to be able to use the $username value pulled from LDAP and match it to the 'username' value pulled from MySQL to set the phone and email variables.

Do not use Mysql, it is obsolete module and its own documentation recommends to use DBI. DBI has selectall_arrayref method which you can use to get all records from the table. If you want to be able to get phone and email by username you can store result into hash like this (not tested):

Always use the single quotes. WRT the perl API, you can also use placeholders

Sorry, bad advise:

"Always use single quotes" is too much work. There is no need to quote numbers, doing so makes the job harder for the database.

"Always use single quotes" is just plain wrong. It makes people think "just add the magic quotes and everything will be well". Even with the quotes, the SQL is still vulnerable to SQL injection. You really want proper quoting here.

While most databases use single quotes, some exotic ones may use other quotes. So, you first need to find out HOW to quote properly.

Luckily, all this has already been done in DBI and the various DBDs, there is no need to reinvent the wheel. So, the last part should really read: "You SHOULD use placeholders". Unfortunately, DBI does not force you to use them, because that would be too much work. It really should, so you better read that advice as "You MUST use placeholders".

Some technical background: DBI guarantees that you can use "?" placeholders with each and every database supported by DBI, even if the database itself does not support placeholders. DBI will automatically insert all bind values, properly quoted, into the SQL statement before it is passed to the database. Since most DBs do support placeholders, using them costs really nothing. Even better, because most DB APIs use seperate ways for the SQL statement and the bind values, there is absolutely no need to quote anything at the Perl or the DB API level. As a nice side effect, your code can work with every database that understands SQL (unless you use some DB-specific, non-standard SQL). And, for extra bonus points, the prepared SQL statement with placeholders can be cached.

Imagine you need to run 20.000 queries (insert, select, update, whatever) against a database, that differ only in the values used. Using hardcoded SQL, you have to generate 20.000 SQL statements, pass them to the database, have the database parse them 20.000 times, and finally execute the one of the 20.000 parsed SQL statements, returning a result. With placeholders, you write ONE query containing placeholders, pass that query ONCE to the database, have the database parse that query ONCE, and finally you play ping-pong with the database: One set of values in, one result out, without any parsing or quoting, as fast as your Perl code can handle the data.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

I believe others have already given appropriate Perl advice. However, if you prefer not to select all rows from the table, which may make or may not make sense depending on the size of the table, you can use a for loop to build a list of user names, and then structure your SQL select statement to use "IN".