Better way of getting values from table without looping 300 queries - php

I have a query and a loop written that lists all the rows from a mysql table ("records") formatted in a HTML table.
One of the fields is "subject_id" which is an integer. I also have a table named "subjects" which corresponds to the same "subject_id" in the records table. Only two fields are in the "subjects" table, is an auto-index ID integer and a varchar(1024) for the subject title.
The value that returns from the "records" table is an integer. I want to perform a lookup on the integer from the "records" table for each row to output the text equivalent from the "subject_id" field.
My first notion, the kindergarten way, would be to throw in another query within the loop, effectively increasing my number of queries from 300 to 600 to load the page (no pagination is needed).
What would be a better way of this "sub query" aside from adding 300 more queries?
Edit:
I'm pulling the data from the table using a while loop and echoing my variable $r_subject (from: $r_subject = mysql_result($result,$a,"subject");). The value returned from the initial records table is INT. I want to take the $r_subject and then check it against the SUBJECTS table to get the string name associated with that INT id.

It's hard to know exactly what you need without seeing code, but from what I gather, you have 2 tables, one has the ID, the other has the text, so you would want to use a join.
The second thing is, you'll want to look at whether or not you really need 300 queries in the first place. That's a lot of queries to run and you should only need to run that many queries when you're running a bulk insert/update or something of that nature; other than that, you most likely could reduce that number substantially.

select
A.*,
B.title
from
records A,
subjects B
where
B.subject_id = A.subject_id
That's a single query that will produce all of the data you need for your page.

select
subjects.SubjectTitle,
records.whateverFieldYouWant,
records.AnyOtherField
from
records
join subjects
on records.subject_id = subjects.subject_id
where
records.subject_id = TheOneSubjectYouWant
but can't confirm without actual structure of tables and some sample data displayed showing proper context of what you are expecting out

Related

Select column(s) names based on user entry with a MYSQL query

Using PHP a secure user will enter a Ref (ex. NB093019) a query will be used to determine which PO(s) have that Ref and if they have any quantity. The issue is that we have 86 columns to check if that Ref is in and then once it finds what column it is in how to check the corresponding column that contains that quantity( the table cannot be edited).
I can make this work with 86 if else statements in PHP and then more if else statements inside of each PHP statement. I have no launching point once i do the initial query.
select 'remainder'as prefix, po, *comments,*GuideRef, *Qty
from remainder
where ('NB092419')IN (NWANTcomments,NWANTGuideRef,NWANTpreviouscomments,
NWANTpreviousGuideRef,NWANTprevious2comments,
NWANTprevious2GuideRef, BPrev2GuideRef,
BPrev2comments, BPrevGuideRef, BPrevcomments,
aGuideRef, Mcomments,MGuideRef,acomments,
MAGuideRef,BOGuideRef )
group by po
I have removed some of the in() information so it is not so long also the *comments, *GuideRef, *Qty would be decided by which one of the columns in the IN() statement returns information. Is this even possible
You could perhaps write an SQL that writes an SQL:
select REPLACE(
'SELECT ''{colstub}GuideRef'' as which, {colstub}Qty FROM remainder WHERE {colstub}Ref like ''%somevalue%'' UNION ALL',
'{colstub}',
REPLACE(column_name, 'GuideRef', '')
)
FROM information_schema.columns
WHERE table_name = 'remainder' and column_name LIKE '%Ref'
It works like "pull all the column names out of the info schema where the column name is like %guideref, replace guideref with nothing to get just the fragment of the column name that is varied: NWANTguideref -> NWANT, NWANTpreviousguideref -> NWANTprevious ... then uses this stub to form a query that gives a string depicting the column name, the qty from the quantity column, where the relevant guideref column is LIKE some value"
If you run this it will produce a result set like:
SELECT 'aGuideRef' as which, aQty FROM table WHERE aGuideRef LIKE '%lookingfor%' UNION ALL
SELECT 'bGuideRef' as which, bQty FROM table WHERE bGuideRef LIKE '%lookingfor% ...
So it's basically utputted a load of strings that are SQLs in themselves. It might need a bit of fine tuning, and hopefully all your columns are reliably and rigidly like xQty, xGuideRef, xComments triplets, but it essentially writes most the query for you
If you then copy the result set out of the results grid and paste it back into the query window, remove the last UNION ALL and run it, it will search the columns and tell you where it was found as well as the quantity
It's not too usable for a production system, but you could do the same in php- run the query, get the strings into another sql command, re-run it..
I would suggest you consider changing your table structure though:
prefix, qty, guideref, comments
You shouldn't have 86 columns that are the mostly same thing; you should have one column that is one of 86/3 different values then you can just query the guideref and the type. If this were an address table, I'm saying you **shouldn't* have HomeZipcode, WorkZipcode, UniversityZipcode, MomZipcode, DadZipcode.. and every time you want to store another kind of address you add more columns (BoyfriendZipcode, GirlfriendZipcode, Child1Zipcode...). Instead if you just had an "addresstype" column then you can store any number of different kinds of addresses without recompiling your app and changing your db schema
You can use this technique to re-shape the table - write an SQL that writes a bunch of UNION ALL sqls (without WHERE clauses), one of the columns should be the "recordtype" column (from colstub) and the other columns should just be "qty", "guide", "comments". Once you have your result set with the unions you can make a table to hold these 4 things, and then place INSERT INTO newtable at the head of the block of unions

Combine queries to grab foreign key value from different able based on result in mssql

I have to work with a mssql database that I have no control over, so sadly, I can't change the structure at all. This database is setup so that there are 2 tables Entry and Area. In the Area table, there is a column sArea that I need to look up based on a value ixEntry. In the Entry table, I can do a look up (the variables are PHP variables):
SELECT sTitle,ixCategory,ixArea FROM Entry WHERE ixEntry='$ixEntry'
and then do a second query
SELECT sArea FROM Area WHERE ixArea='{$return['ixArea']}'
Which works just fine, except with the way that the network is setup, there is considerably more overhead time with two queries.
How can I combine these two queries so that I have a result that would be the equivalent of SELECT sTitle,ixCategory,sArea FROM Entry WHERE ixEntry='$ixEntry' as if sArea were in the Entry table, not ixArea?
SELECT a.sArea FROM Entry e
INNER JOIN Area a ON e.ixArea = a.ixArea
WHERE e.ixEntry='$ixEntry'

MySQL - How to update two tables with one query where table 2 value is true?

Okay, I am trying to update two tables without using PHP and querying a loop.
Table one: users
Table two: traits
BOTH tables have a matching row "ID" (so ID 1 in "users" is also ID 1 in "traits").
TABLE 1 has two rows that need updating: "HP" and "EXP".
TABLE 2 has one row: "STUFF".
I need a simple query to update HP and EXP ONLY if STUFF = 0.
So something like:
UPDATE users,traits
SET
traits.hp = 3,
traits.exp = 10
WHERE
traits.hp < traits.maxhp
AND users.stuff = 0;
This query seems to work, but it is very slow. Is there a better way?
Thank you!
-Josh
Depending on the table size, I would recommend creating a couple indexes on those table columns (traits.hp, traints.maxhp and users.stuff) to help keep the query quick.
Also, make sure that your traits.hp and traits.maxhp are set as some sort of numerical (eg. INT) type, otherwise the server will need to try and convert it on-the-fly, which could slow things down as well.

SQL check if next row doesn't exist

I have an MsSQL server and what I am doing is selecting rows from the table. Currently I have two rows so I was wondering how would I check if there are no other rows after second one without making another query?
For example
table users
id name pass
1 joe 123
2 bob abc
How would I check if there is no row after 2 with just a query? I am willing to combining it with my current query, which just selects the data.
You can return the number of rows in your query as another column:
SELECT id, name, pass, count(*) over () as rows
FROM users
Keep in mind that this is telling you the number of rows returned by the query, not the number of rows in the table. However, if you specify a "TOP n" in your select, the rows column will give you the number of rows that would have been returned if you didn't have "Top n"
If you're trying to paginate the trick is to query one more record than you actually need for the current page. By counting the result (mysql_num_rows) and comparing that to your page size, you can then decide if there is a 'next page'.
If you were using mysql you could also use SQL_CALC_FOUND_ROWS() in your query, which calculates the number of rows that would be returned without the LIMIT clause. Maybe there is an equivalent for that in MsSQL?
I assume that you are inserting manually the first 2 rows of your table.
According to that, my idea is to just do a select where the id is more than 2 like this:
SELECT * FROM users WHERE id > 2;
I also assume that you are using PHP so mysql_num_rows will return you 0 if no data is found, otherwise it will return you the number of rows from your query and now you know that you need to do a while or some loop to retrieve the data after id number 2.

Completely arbitrary sort order in MySQL with PHP

I have a table in MySQL that I'm accessing from PHP. For example, let's have a table named THINGS:
things.ID - int primary key
things.name - varchar
things.owner_ID - int for joining with another table
My select statement to get what I need might look like:
SELECT * FROM things WHERE owner_ID = 99;
Pretty straightforward. Now, I'd like users to be able to specify a completely arbitrary order for the items returned from this query. The list will be displayed, they can then click an "up" or "down" button next to a row and have it moved up or down the list, or possibly a drag-and-drop operation to move it to anywhere else. I'd like this order to be saved in the database (same or other table). The custom order would be unique for the set of rows for each owner_ID.
I've searched for ways to provide this ordering without luck. I've thought of a few ways to implement this, but help me fill in the final option:
Add an INT column and set it's value to whatever I need to get rows
returned in my order. This presents the problem of scanning
row-by-row to find the insertion point, and possibly needing to
update the preceding/following rows sort column.
Having a "next" and "previous" column, implementing a linked list.
Once I find my place, I'll just have to update max 2 rows to insert
the row. But this requires scanning for the location from row #1.
Some SQL/relational DB trick I'm unaware of...
I'm looking for an answer to #3 because it may be out there, who knows. Plus, I'd like to offload as much as I can on the database.
From what I've read you need a new table containing the ordering of each user, say it's called *user_orderings*.
This table should contain the user ID, the position of the thing and the ID of the thing. The (user_id, thing_id) should be the PK. This way you need to update this table every time but you can get the things for a user in the order he/she wants using ORDER BY on the user_orderings table and joining it with the things table. It should work.
The simplest expression of an ordered list is: 3,1,2,4. We can store this as a string in the parent table; so if our table is photos with the foreign key profile_id, we'd place our photo order in profiles.photo_order. We can then consider this field in our order by clause by utilizing the find_in_set() function. This requires either two queries or a join. I use two queries but the join is more interesting, so here it is:
select photos.photo_id, photos.caption
from photos
join profiles on profiles.profile_id = photos.profile_id
where photos.profile_id = 1
order by find_in_set(photos.photo_id, profiles.photo_order);
Note that you would probably not want to use find_in_set() in a where clause due to performance implications, but in an order by clause, there are few enough results to make this fast.

Categories