(Sorry for such a long post... I thought others may benefit as well as ED)
Ed, Here is an example using a CURSOR and a TEMPORARY TABLE to do something similar to what you want (I think!): ========== CREATE TABLES ========== mysql> show create table mydatabases; CREATE TABLE `mydatabases` ( `database_id` int(11) NOT NULL auto_increment, `database_name` varchar(50) NOT NULL, PRIMARY KEY (`database_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | mysql> show create table mytables; CREATE TABLE `mytables` ( `table_id` int(11) NOT NULL auto_increment, `database_id` int(11) NOT NULL, `table_name` varchar(50) NOT NULL, PRIMARY KEY (`table_id`), KEY `FK_mytables_mydatabases` (`database_id`), CONSTRAINT `FK_mytables_mydatabases` FOREIGN KEY (`database_id`) REFERENCES `mydatabases` (`database_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | mysql> show create table myrecords; CREATE TABLE `myrecords` ( `record_id` int(11) NOT NULL auto_increment, `table_id` int(11) NOT NULL, `record_id_in_table` int(11) NOT NULL, PRIMARY KEY (`record_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | ========== TEST DATA ========== mysql> select * from mydatabases; +-------------+---------------+ | database_id | database_name | +-------------+---------------+ | 1 | test | | 2 | test2 | | 3 | test3 | +-------------+---------------+ 3 rows in set (0.00 sec) mysql> select * from mytables; +----------+-------------+------------+ | table_id | database_id | table_name | +----------+-------------+------------+ | 1 | 1 | Books | | 2 | 1 | CDs | | 3 | 1 | DVDs | | 4 | 1 | Records | +----------+-------------+------------+ 4 rows in set (0.00 sec) mysql> select * from myrecords; +-----------+----------+--------------------+ | record_id | table_id | record_id_in_table | +-----------+----------+--------------------+ | 1 | 1 | 1 | | 2 | 1 | 2 | | 3 | 1 | 3 | | 4 | 1 | 4 | | 5 | 1 | 5 | | 6 | 2 | 1 | | 7 | 2 | 2 | | 8 | 2 | 3 | | 9 | 2 | 4 | | 10 | 3 | 1 | | 11 | 3 | 2 | | 12 | 3 | 3 | | 13 | 3 | 4 | | 14 | 3 | 5 | | 15 | 3 | 6 | +-----------+----------+--------------------+ 15 rows in set (0.00 sec) mysql> select * from myinventory; +--------------+---------+-------------+----------+-----------+ | inventory_id | user_id | database_id | table_id | record_id | +--------------+---------+-------------+----------+-----------+ | 1 | 1 | 1 | 1 | 1 | | 2 | 1 | 1 | 1 | 2 | | 3 | 1 | 1 | 2 | 1 | | 4 | 1 | 1 | 3 | 2 | | 5 | 2 | 1 | 1 | 3 | | 6 | 2 | 1 | 1 | 4 | | 7 | 2 | 1 | 2 | 4 | | 8 | 2 | 1 | 3 | 3 | +--------------+---------+-------------+----------+-----------+ 8 rows in set (0.02 sec) mysql> select * from books; +---------+-------------------------------+ | book_id | book_name | +---------+-------------------------------+ | 1 | MySQL Tutorial | | 2 | Learning XML | | 3 | XML IE5 | | 4 | Programming Visual Basis 2005 | | 5 | Learning C# | +---------+-------------------------------+ 5 rows in set (0.00 sec) mysql> select * from cds; +-------+---------------------------------+ | cd_id | cd_name | +-------+---------------------------------+ | 1 | Pink Floyd Meddle | | 2 | Rush Chronicles | | 3 | Led Zepplin IV | | 4 | Frank Marino & Mahogany Rush IV | +-------+---------------------------------+ 4 rows in set (0.00 sec) mysql> select * from dvds; +--------+---------------------------+ | dvd_id | dvd_name | +--------+---------------------------+ | 1 | Dances With Wolves | | 2 | Pink Floyd Live at Pompei | | 3 | Braveheart | | 4 | Saving Private Ryan | | 5 | Ice Age | | 6 | Cars | +--------+---------------------------+ 6 rows in set (0.00 sec) ========== STORED PROCEDURE ========== DELIMITER $$ DROP PROCEDURE IF EXISTS `test`.`test_looping`$$ CREATE PROCEDURE `test_looping`(IN intUserID int ) BEGIN /* ------------------------------------------------------------------- Declare variables to use. ------------------------------------------------------------------- */ DECLARE blnNoMoreRows BOOLEAN DEFAULT FALSE; DECLARE strDatabaseName VARCHAR(50); DECLARE strTableName VARCHAR(50); DECLARE intRecordIdInTable INT(11); DECLARE strFieldID VARCHAR(50); DECLARE strFieldName VARCHAR(50); DECLARE strSQL VARCHAR(2000); /* ------------------------------------------------------------------- Declare CURSOR and HANDLER. ------------------------------------------------------------------- */ DECLARE Cursor1 CURSOR FOR SELECT d.database_name, t.table_name, r.record_id_in_table FROM myInventory i JOIN myDatabases d ON i.database_id = d.database_id JOIN myTables t ON i.table_id = t.table_id JOIN myRecords r ON i.record_id = r.record_id WHERE i.user_id = intUserID; DECLARE CONTINUE HANDLER FOR NOT FOUND SET blnNoMoreRows = TRUE; /* ------------------------------------------------------------------- Create a temporary table to hold the results. ------------------------------------------------------------------- */ DROP TEMPORARY TABLE IF EXISTS TempResults; CREATE TEMPORARY TABLE TempResults ( user_id INT(11) NOT NULL, database_name VARCHAR(50) NOT NULL, table_name VARCHAR(50) NOT NULL, record_id_in_table INT(11) NOT NULL, item_name VARCHAR(50) NOT NULL); /* ------------------------------------------------------------------- Loop through cursor. ------------------------------------------------------------------- */ OPEN Cursor1; REPEAT FETCH Cursor1 INTO strDatabaseName, strTableName, intRecordIdInTable; IF NOT blnNoMoreRows THEN CASE LOWER(strTableName) WHEN "books" THEN SET strFieldID = "book_id"; SET strFieldName = "book_name"; WHEN "cds" THEN SET strFieldID = "cd_id"; SET strFieldName = "cd_name"; WHEN "dvds" THEN SET strFieldID = "dvd_id"; SET strFieldName = "dvd_name"; END CASE; -- Here is where you build the dynamic SQL SET @strSQL = CONCAT( "SET @strItemName = ", "(", "SELECT ", strFieldName, " FROM `", strDatabaseName,"`.`",strTableName,"`", " WHERE ", strFieldID, " = ", intRecordIdInTable, ")"); PREPARE stmt1 FROM @strSQL; EXECUTE stmt1; DEALLOCATE PREPARE stmt1; -- Save these results into the temporary table INSERT INTO TempResults SELECT intUserID, strDatabaseName, strTableName, intRecordIdInTable, @strItemName; END IF; UNTIL blnNoMoreRows END REPEAT; CLOSE Cursor1; /* ------------------------------------------------------------------- Return the results from the temporary table. ------------------------------------------------------------------- */ SELECT * FROM TempResults; END$$ DELIMITER ; ========== TEST CALLS ========== mysql> CALL test_looping(1); +---------+---------------+------------+--------------------+----------- ----------------+ | user_id | database_name | table_name | record_id_in_table | item_name | +---------+---------------+------------+--------------------+----------- ----------------+ | 1 | test | Books | 1 | MySQL Tutorial | | 1 | test | Books | 2 | Learning XML | | 1 | test | CDs | 1 | Pink Floyd Meddle | | 1 | test | DVDs | 2 | Pink Floyd Live at Pompei | +---------+---------------+------------+--------------------+----------- ----------------+ 4 rows in set (0.31 sec) Query OK, 0 rows affected, 1 warning (0.33 sec) mysql> CALL test_looping(2); +---------+---------------+------------+--------------------+----------- ----------------------+ | user_id | database_name | table_name | record_id_in_table | item_name | +---------+---------------+------------+--------------------+----------- ----------------------+ | 2 | test | Books | 3 | XML IE5 | | 2 | test | Books | 4 | Programming Visual Basis 2005 | | 2 | test | CDs | 4 | Frank Marino & Mahogany Rush IV | | 2 | test | DVDs | 3 | Braveheart | +---------+---------------+------------+--------------------+----------- ----------------------+ 4 rows in set (0.27 sec) Query OK, 0 rows affected (0.28 sec) Hope this helps. Randall Price Secure Enterprise Technology Initiatives Microsoft Implementation Group Virginia Tech Information Technology 1700 Pratt Drive Blacksburg, VA 24060 Email: [EMAIL PROTECTED] Phone: (540) 231-4396 -----Original Message----- From: Octavian Rasnita [mailto:[EMAIL PROTECTED] Sent: Wednesday, June 27, 2007 2:53 PM To: Ed Lazor; Price, Randall Cc: mysql@lists.mysql.com Subject: Re: select statement with variable for table_reference? Yes it is a good idea to store in a table information about which other tables should be searched. I don't know how these queries can be made using only SQL. I think that it could be made in the programming language you use. For example, first get the list of tables that should be searched (from that index table), then create that SQL query that uses union using only those tables. It shouldn't be too hard to do. For example, after searching the index table, it could return that you need to search in the books and CDS tables. Then you could create that sql query like: $sql = ""; for("books", "cds") { $sql .= join " union ", "(select id, title, from $_)"; } $sql .= " where ... order by ... limit ..."; So the sql query will search only in the needed tables. Octavian ----- Original Message ----- From: "Ed Lazor" <[EMAIL PROTECTED]> To: "'Octavian Rasnita'" <[EMAIL PROTECTED]>; <[EMAIL PROTECTED]> Cc: <mysql@lists.mysql.com> Sent: Wednesday, June 27, 2007 8:02 PM Subject: RE: select statement with variable for table_reference? > Hi Octavian, > > First, thanks for helping out. I really appreciate it. Thanks to you > also > Randall. > >> I am not sure I understand what you want. >> >> If you want to search for all cds, and books, and dvds based on a certain >> criteria, you can use that method I've told you about. > > Randall said it best. I have one table that has information about what > other tables to search in. > > One table serves as an index of what's in a user's inventory while the > actual product information resides in other tables. > > The user inventory table has fields for user_id, database_id, table_id, > and > record_id. > > There are also two other "helper" tables. One table (inventory_databases) > contains a list of databases with their id and name. Another table > (inventory_tables) contains a list of tables with their id and name. Both > of these tables help map from the user's inventory to where product > information resides. > > An example record from the inventory table would have data like this: > > user_id 33 > database_id 1 > table_id 1 > record_id 234234 > > > I can look up the name of the database using database_id in the > inventory_databases table. I can look up the name of the table using > table_id in the inventory_tables table. > > All of the other product tables have an id field that corresponds to the > record_id. > > Back to the example above, database_id 1 is the products1 database and > table_id 1 is the books table. That means user id 33 has the book id > 234234 > in products1.books. > > Ok, that describes what I'm working with. As for what I'm trying to > accomplish, I'm trying to reduce the number of queries required for > pulling > together basic information about the user's inventory. Why is that? > Well... > > Right now I run one query the inventory table for all information specific > to the user. Next, I use this information and run additional queries to > get > the actual product information. If the user has 1000 items in their > inventory, I end up having to run 1 + 1000 queries. This can't be helped > in > situations where I refer to fields that are unique to each type of item > (aka > table). It seems like I should be able to avoid this though when dealing > with a common field like title. I'm just not sure how to go about it. > > Using UNIONS is the only single query to work so far. Like I mentioned > though, this requires a UNION for every table that product information is > being stored in. If the first table can tell us where the data resides, > it > seems like we can use it to reduce the number of UNIONS required. > > Randall, your use of prepared statements and stored procedures seems like > a > good approach. It might provide a way to dynamically generate the product > query. When I look at this: > > SET @strOtherTable = (SELECT other_table_name FROM first_table WHERE > ...); > SET @strSQL = CONCAT("SELECT ... FROM ", @strOtherTable, " WHERE..."); > > The first thing I automatically think of is that the first select will > very > likely have more than one record in the result set. Is there a way to > loop > through the results to concatenate everything into the set of UNIONS? > > Ed > > >> >> May you want sometimes to search only in fewer tables that you know >> before >> making the query? If yes, then you can create more separate queries that >> search only in those tables. >> >> If you want to search only in the tables that have data about you want to >> search, you can't do it, because you don't know if those tables contain >> what >> you want before searching in them. >> >> But if those tables have well defined indexes on the keys you are >> searching >> for, that search will be very fast, especially if some of the tables >> don't >> contain records that match your criteria. >> >> I hope I understood correctly what you want. >> >> If you just want to specify a search criteria for each table separately, >> you >> can do it for each table in the (select ... where ...) and if you want to >> specify a search criteria for all the records of those unions, you can do >> it >> in a final where ... that's outside of those params. >> >> Octavian >> >> ----- Original Message ----- >> From: "Ed Lazor" <[EMAIL PROTECTED]> >> To: "'Octavian Rasnita'" <[EMAIL PROTECTED]>; <mysql@lists.mysql.com> >> Sent: Tuesday, June 26, 2007 11:37 PM >> Subject: RE: select statement with variable for table_reference? >> >> >> > Ok, I used your approach like this: >> > >> > -------------------------------------------------------------- >> > select i.scanned_barcode, v.title from inventory as i >> > left join version as v on i.record_id = v.id >> > where >> > i.database_id = '1' AND i.table_id = '1' AND >> > i.user_id = '33' and category_id = '766') >> > >> > UNION >> > >> > (select i.scanned_barcode, v.title from inventory as i >> > left join amg.dvd as v on i.record_id = v.id >> > where >> > i.database_id = '2' AND i.table_id = '3' AND >> > i.user_id = '33' and category_id = '766') >> > >> > >> > order by title DESC >> > -------------------------------------------------------------- >> > >> > It "works" like you're suggesting. I have to add a union for every one >> of >> > the tables data is being stored in. That means I end up selecting >> > something >> > from every product table, regardless of whether the user actually has >> > something in there or not. Improving on this idea would be finding a >> way >> > to >> > just query the relevant tables... some sort of conditional union. Any >> > ideas? >> > >> > -Ed >> > >> > >> > >> >> -----Original Message----- >> >> From: Octavian Rasnita [mailto:[EMAIL PROTECTED] >> >> Sent: Tuesday, June 26, 2007 1:02 PM >> >> To: Ed Lazor; mysql@lists.mysql.com >> >> Subject: Re: select statement with variable for table_reference? >> >> >> >> I am using the following method for doing this, but I am sure it is >> >> not >> >> the >> >> best one: >> >> >> >> (select id, title, author, 'book' as type from books) >> >> union >> >> (select id, title, author, 'cd' as type from cds) >> >> union >> >> (select id, title, author, 'dvd' as type from dvds) >> >> where ... >> >> order by ... >> >> limit ...; >> >> >> >> Octavian >> > >> > >> >> >> -- >> MySQL General Mailing List >> For list archives: http://lists.mysql.com/mysql >> To unsubscribe: >> http://lists.mysql.com/[EMAIL PROTECTED] > > > -- MySQL General Mailing List For list archives: http://lists.mysql.com/mysql To unsubscribe: http://lists.mysql.com/[EMAIL PROTECTED]