I'm working on my project in php [handling students attendance system]. I have a list of students along with their unique id[jntuno] and I need to create a database in mysql for storing the daily attendance of each student for each subject. So I created my tables in this way :
I have a table students in mysql with the following fields and data in it :
now I want to create a new table with the each of the values in the jntuno field as a columns of my new table.
I want my new table [let us name it attendance] to have columns like this :
+------------+-----------+----------+-----------+-----------+
|11341A0501 |11341A0502 |11341A0503|11341A0504 |11341A0505 |......
+------------+-----------+----------+-----------+-----------+
| | | | | |
How to do this in mysql ?
I will later add 3 fields to the attendance table namely :
-> date[the date on which a particular subject is taught] ,
->subject[the name of the subject taught] and
->hours taught[the number of hours for which a particular subject is taught(can be 1 or 2 or 3 ... upto 6)]
every subject taught on a particular date will be adding a new row to the attendance table
Example:
+------------+-----------+-----------------+------------+-----------+----------+-----------+-----------+
|date |subject | classes taught |11341A0501 |11341A0502 |11341A0503|11341A0504 |11341A0505 |..
+------------+-----------+-----------------+------------+-----------+----------+-----------+-----------+
|2013-09-31 |OOPS |3 |2 |3 |0 |1 |3 |
I choose the tables in this way so that the entry of attendance into the table would be more faster.
But many call this a BAD DATABASE STRUCTURE . So please suggest me if there's some other good and efficient database design for my problem
Create the new table with the following statements:
select #s:=concat('create table students_col (',group_concat(jntunno,' CHAR(10)' order by slno),')') from students;
prepare stmt from #s;
execute stmt;
deallocate prepare stmt;
observe how the CREATE TABLE is constructed using the group_concat
Demo: SQL Fiddle
In case you also want to insert the names, this is the statement to it:
select #s:=concat('insert into students_col values (',group_concat(concat('"',name,'"') order by slno),')') from students;
prepare stmt from #s;
execute stmt;
deallocate prepare stmt;
select * from students_col;
Here is my whole trail:
mysql> drop table if exists students;
Query OK, 0 rows affected (0.00 sec)
mysql> create table students (slno integer, jntunno char(10), name varchar(50));
Query OK, 0 rows affected (0.07 sec)
mysql> insert into students values (1,'1134A0501','ADARI GOPI');
Query OK, 1 row affected (0.00 sec)
mysql> insert into students values (2,'1134A0502','BALU');
Query OK, 1 row affected (0.00 sec)
mysql> insert into students values (3,'1134A0503','GEETHA');
Query OK, 1 row affected (0.00 sec)
mysql> drop table if exists students_col;
Query OK, 0 rows affected (0.00 sec)
mysql> select #s:=concat('create table students_col (',group_concat(jntunno,' CHAR(10)' order by slno),')') from students;
+-----------------------------------------------------------------------------------------------+
| #s:=concat('create table students_col (',group_concat(jntunno,' CHAR(10)' order by slno),')') |
+-----------------------------------------------------------------------------------------------+
| create table students_col (1134A0501 CHAR(10),1134A0502 CHAR(10),1134A0503 CHAR(10)) |
+-----------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> prepare stmt from #s;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> execute stmt;
Query OK, 0 rows affected (0.21 sec)
mysql> deallocate prepare stmt;
Query OK, 0 rows affected (0.01 sec)
mysql>
mysql> select #s:=concat('insert into students_col values (',group_concat(concat('"',name,'"') order by slno),')') from students;
+------------------------------------------------------------------------------------------------------+
| #s:=concat('insert into students_col values (',group_concat(concat('"',name,'"') order by slno),')') |
+------------------------------------------------------------------------------------------------------+
| insert into students_col values ("ADARI GOPI","BALU","GEETHA") |
+------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> prepare stmt from #s;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> execute stmt;
Query OK, 1 row affected (0.00 sec)
mysql> deallocate prepare stmt;
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> select * from students_col;
+------------+-----------+-----------+
| 1134A0501 | 1134A0502 | 1134A0503 |
+------------+-----------+-----------+
| ADARI GOPI | BALU | GEETHA |
+------------+-----------+-----------+
1 row in set (0.00 sec)
mysql>
This procedure will do the work:
DELIMITER ||
DROP PROCEDURE IF EXISTS `test`.`pivot`;
CREATE PROCEDURE `test`.`pivot`()
MODIFIES SQL DATA
BEGIN
DROP TABLE IF EXISTS `test`.`new_table`;
SELECT GROUP_CONCAT(CONCAT(`jntunno`, ' CHAR(10) NOT NULL') SEPARATOR ', ') FROM `test`.`students` INTO #sql;
SET #sql := CONCAT('CREATE TABLE `test`.`new_table` (', #sql, ') ENGINE=InnoDB;');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #sql := NULL;
END;
||
DELIMITER ;
If you cannot use stored procedures, you can easily translate that code into PHP, or any language you use.
create table new_table
select distinct jntuno from students;
or
create table new_table (jntuno varchar(10));
insert into new_table
select distinct jntuno from students;
try
create table new_table (jntuno varchar(10),fieldsname varchar(10));
insert into new_table(jntuno,fieldsname)
values(select distinct jntuno from s tudents,'test');
I'm going to try an answer your question of how to better design this DB:
The Explanation:
Instead of having a column for each student and I assume a row for each day, you should set the table up to have a row for each student x by each day and you can use foreign keys to enforce data integrity
The main reason for this is generally something like the number of students is not a static number. In order to optimize your data usage in a setup like this you would essentially need to recreate the table every time a student is added or removed.
So if you start out with 30 students you then have a table with 30 columns, if then the number of students drops to 15 every time you add a record you are creating 15 unused values and this will gradually take up a lot more storage than you actually need.
Solution:
If you structure your attendance table like this:
attendance ID | JNTUNO | Date | Subject | Hours
Attendance id will simply be a unique identifier for the row, I would suggest either a guid or an auto incremented int
JNTUNO would be a foreign key, pointing back to your Student table
This way on the scenario I presented earlier, with 30 students you will add 30 rows every day with 5 values each but when your number of students changes to 15 you add only 15 rows.
I don't know MYSQL syntax very well but if you'd like I can try to piece together a concrete implementation if my explanation isn't clear; just let me know.
You don't want to be adding columns every time you add a student.
I'd design it like this:
Table: Attendance
Columns:
Date
Subject
ClassNumber
Missed_jntuno
Then you add a row for each student/class combo that is missed (or, if students miss more than they attend, you might want to flip that to a Attended_jntuno field instead and add the row when they make it to class — or if you're really feeling completest, always write a row for every student and then have another bit/boolean column for attended or not).
One advantage to this way is that you can see which classes got which students in addition to a daily sum. Another is that this is much friendlier to things like OLAP cubes for flexible reporting.
declare #s as varchar(8000);
declare #s2 as varchar(25);
set #s ='create table attendance (';
declare s1 cursor
for
select jntunno from students
OPEN s1
fetch next from s1 into #s2
set #s = #s +'['+#s2 +'] numeric(4,2)'
fetch next from s1 into #s2
WHILE ##FETCH_STATUS = 0
BEGIN
set #s = #s +',['+#s2 +'] numeric(4,2)'
fetch next from s1 into #s2
end
CLOSE s1 -- close the cursor
DEALLOCATE s1
set #s = #s+')'
exec(#s)
Basic database design is jumping up right now and shouting in your face: "You're doing it wrong!".
What you're trying to do here is put a many to many relationship in 1 table, while it should actually be in 3 tables.
What you should do is keep your student table as-is and add a subjects table with 1 row for each subject, but not including the date.
Then you want to have another table Attendance with a reference column to Student ID, a reference column to subject ID, a Date field and a Presence field.
What you're trying to do right now is trying to store what's basically volatile data in your metadata about your table, which you should never do. For example, what if you have a student join your school 1 week into the grade? then your table suddenly gets an extra column with no values for the first week.
In addition, your system means that database queries are much harder, since you're storing data you want to filter on in your column header. Other people in here have given a number of reasons why this is a bad idea.
Related
I am having difficult getting a procedure to update a table in the way I require. I am using phpmyadmin on my local computer. In phpmyadmin I can put the following code into the SQL tab and one row will be updated:
SET `adjCost` = 22.05 WHERE `Name` LIKE CONCAT('magic', '%') AND `idKey` = '2016fulham02345';
As expected and wanted, IF the name begins with magic AND the idKey is '2016fulham02345' THEN the adjCost is updated to 22.05.
There will be between 2 and 50 rows with the same idKey. The Name will never be repeated in a set with the same idKey.
I created a procedure with the following parameters:
IN idK VARCHAR 255 Charset
IN aName VARCHAR 255 Charset
IN cost FLOAT 5,2
BEGIN
UPDATE `raceresults` SET `adjCost` = cost WHERE `Name` LIKE CONCAT(aName, '%') AND `idKey` = idK;
END
When I run this procedure it updates ALL adjCost where the idKey = idk and (seems) to ignore the name parameter.
I have tried concatenating the name string first:
BEGIN
SELECT CONCAT(aName, '%') INTO #str;
UPDATE `raceresults` SET `adjCost` = cost WHERE `Name` = #str AND `idKey` = idK;
END
but to no avail.
I looked through w3schools, stackoverflow and google and have not been able to find the answer.
My question is:
How can I correct my procedure to get it to work as I would like?
UPDATE: as requested.
CREATE DEFINER=`root`#`localhost` PROCEDURE `importAltUpdateAjdCost`(IN `idK` VARCHAR(255), IN `aName` VARCHAR(255), IN `cost` FLOAT(5,2))
NO SQL
BEGIN
UPDATE `costingPP`
SET `adjCost` = cost
WHERE
`Name` LIKE CONCAT(aName, '%')
AND
`idKey` = idK;
END
To get this, I selected export on my list of procedures on phpmyadmin.
I'm not entirely sure what or how you did, but here's what I did and it instantly worked. Since you didn't specify MySQL version, I used 5.7.
EDIT: Now as I went back to see your procedure creation statement I realised that NO SQL was introduced in MySQL 8.0. Since your procedure clearly is SQL then please remove the NO SQL and re-create the procedure.
I'm leaving my MySQL 5.7 sample here for reference:
1) Created a simple table:
mysql> CREATE TABLE raceresults (
-> idKey VARCHAR(255),
-> Name VARCHAR(255),
-> adjCost FLOAT(5,2)
-> );
Query OK, 0 rows affected (0.06 sec)
2) Here we insert a sample data row:
mysql> INSERT INTO raceresults VALUES ('2016fulham02345', 'magicFlyingHorse', 0.00);
Query OK, 1 row affected (0.01 sec)
3) To create a (STORED) PROCEDURE we have to temporarily set a different delimiter, so query parser wouldn't terminate procedure creation on default semi-colon, as it's used inside the procedure. After delimiter's change we create the procedure and set the delimiter back to semi-colon
mysql> DELIMITER //
mysql> CREATE PROCEDURE update_test(IN idK VARCHAR(255), IN aName VARCHAR(255), IN cost FLOAT(5,2))
-> BEGIN
-> UPDATE `raceresults` SET `adjCost` = cost WHERE `Name` LIKE CONCAT(aName, '%') AND `idKey` = idK;
-> END//
mysql> DELIMITER ;
Query OK, 0 rows affected (0.00 sec)
4) Now let's see how it all works. Before and after the procedure call I'm selecting the rows from database. You can see the cost column value changing:
mysql> SELECT * FROM raceresults;
+-----------------+------------------+---------+
| idKey | Name | adjCost |
+-----------------+------------------+---------+
| 2016fulham02345 | magicFlyingHorse | 0.00 |
+-----------------+------------------+---------+
1 row in set (0.00 sec)
mysql> CALL update_test('2016fulham02345', 'magic', 1.23);
Query OK, 1 row affected (0.02 sec)
mysql> SELECT * FROM raceresults;
+-----------------+------------------+---------+
| idKey | Name | adjCost |
+-----------------+------------------+---------+
| 2016fulham02345 | magicFlyingHorse | 1.23 |
+-----------------+------------------+---------+
1 row in set (0.00 sec)
And now one piece of advise too:
If possible, use only lower case table, column, indexes, functions, procedures, etc... names, while always writing all SQL commands in uppercase (which you did). This is kind of a de facto standard and makes life easier both for you and others reading your code.
I have the following query I want to execute in my stored procedure WITHOUT PREPARING the query, since this gives me problems with OUT to pass back parameters.
DELIMITER //
CREATE PROCEDURE Test (
IN CID BIGINT(20),
IN IDs LONGTEXT
)
BEGIN
#EXECUTE UNDERNEATH QUERY
SELECT * FROM CONCAT('Part1_OfTableName', CID); #CID IS CustomerID
END //
DELIMITER ;
However, this fails and I don't know how to fix the problem.
(Note that in the example I have no spaces in my table name, however in my situation I might have a space in my table name though)
PREPARE should have no bearing on your ability to successfully set OUT parameters of your procedure
SET DELIMITER //
CREATE PROCEDURE test(IN cid INT, IN ids TEXT, OUT out_int INT)
BEGIN
SET #sql = CONCAT('SELECT * FROM `table_', cid, '`', CASE WHEN ids IS NULL THEN '' ELSE CONCAT(' WHERE id IN( ', ids, ')') END);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET out_int = 1;
END//
SET DELIMITER ;
Sample usage:
mysql> CALL test(1, '2,3', #out_int);
+------+
| id |
+------+
| 2 |
| 3 |
+------+
2 rows in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #out_int;
+----------+
| #out_int |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
If you need to return results from a stored procedure using sql statement that must be prepared, you can use an intermediate temp table.
BEGIN
CREATE TEMPORARY TABLE `myresults` blah blah....;
//construct and prepare select you would've used, but start it with an insert like so...
// INSERT INTO `myresults` SELECT ....
// Execute the prepared query
SELECT * FROM `myresults`;
DROP TEMPORARY TABLE `myresults`;
END
...at least I am pretty sure this technique used to work; I've been working more in MSSQL the last couple years.
Something to note:
Temporary tables are connection/session specific, so while safe from a global perspective using a generic name like myresults can be problematic if queries executed earlier on the connection/session (or by a procedure calling this one) use the same name; in practice/paranoia, I tended to use a different guid (in each procedure using this technique) as a prefix for any temporary tables generated within it.
I've reduced my issue down to this simple SP. The column names are getting cached in the SELECT * at the end. I have no idea why or how to stop it. I tried adding SQL_NO_CACHE but that makes no difference.
DROP TABLE IF EXISTS foo;
CREATE TABLE foo(
col1 int,
col2 int);
INSERT INTO foo VALUES(1,2),(3,4),(5,6);
DROP PROCEDURE IF EXISTS mysp;
DELIMITER ;;
CREATE DEFINER=root#localhost PROCEDURE mysp(c INT)
BEGIN
DROP TABLE IF EXISTS mydata;
SET #mycol='col1';
IF c > 0 THEN SET #mycol:='col2';
END IF;
SET #s=CONCAT('CREATE TEMPORARY TABLE mydata AS SELECT ', #mycol, ' FROM foo');
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- The following select call fails on 2nd and subsequent executions of the SP
SELECT SQL_NO_CACHE * FROM mydata;
SELECT "Please see new temp table mydata" as Result;
END ;;
DELIMITER ;
Version
mysql> SELECT VERSION();
+------------+
| VERSION() |
+------------+
| 5.5.15-log |
+------------+
1 row in set (0.00 sec)
First run works fine as expected
mysql> CALL mysp(0);
+------+
| col1 |
+------+
| 1 |
| 3 |
| 5 |
+------+
3 rows in set (0.17 sec)
+----------------------------------+
| Result |
+----------------------------------+
| Please see new temp table mydata |
+----------------------------------+
1 row in set (0.17 sec)
Query OK, 0 rows affected (0.17 sec)
Now if I try and run it again using the other column
mysql> CALL mysp(1);
ERROR 1054 (42S22): Unknown column 'qlgqp1.mydata.col1' in 'field list'
mysql> SELECT #mycol;
+--------+
| #mycol |
+--------+
| col2 |
+--------+
1 row in set (0.00 sec)
If I recreate the storedprocedure again its works
mysql> CALL mysp(1);
+------+
| col2 |
+------+
| 2 |
| 4 |
| 6 |
+------+
3 rows in set (0.18 sec)
+----------------------------------+
| Result |
+----------------------------------+
| Please see new temp table mydata |
+----------------------------------+
1 row in set (0.18 sec)
Query OK, 0 rows affected (0.18 sec)
But if I try switching back to the first column - even if I try dropping the temp table first - it still doesn't work
mysql> CALL mysp(0);
ERROR 1054 (42S22): Unknown column 'qlgqp1.mydata.col2' in 'field list'
mysql> DROP TABLE mydata;
Query OK, 0 rows affected (0.03 sec)
mysql> CALL mysp(0);
ERROR 1054 (42S22): Unknown column 'qlgqp1.mydata.col2' in 'field list'
mysql>
*Additional info asked for by eggyal. Also I tried this on another mysql version with same result. *
mysql> CALL mysp(1);
+------+
| col2 |
+------+
| 2 |
| 4 |
| 6 |
+------+
3 rows in set (0.20 sec)
+----------------------------------+
| Result |
+----------------------------------+
| Please see new temp table mydata |
+----------------------------------+
1 row in set (0.20 sec)
Query OK, 0 rows affected (0.20 sec)
mysql> describe mydata;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| col2 | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)
mysql> CALL mysp(0);
ERROR 1054 (42S22): Unknown column 'test.mydata.col2' in 'field list'
mysql> describe mydata;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| col1 | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)
Interesting development of a fix - changing the last few lines to a prepared statement works - but using exactly the same query as before.
-- The following select call fails on 2nd and subsequent executions of the SP
PREPARE stmt FROM 'SELECT SQL_NO_CACHE * FROM mydata';
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT "Please see new temp table mydata" as Result;
MySQL is reusing the statement that was prepared on the previous execution. It's not really "caching" column names; what it's "caching" (if you will) is the prepared statement.
The easy workaround is to use dynamic SQL statement to gain control over the behavior, and avoid the reuse of the previously prepared statement:
SET #s=CONCAT('SELECT ',#mycol,' FROM mydata');
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
It's not matter of the column names being "cached", or the results of the query being cached. It's a performance optimization; it's a matter of that statement already being prepared, within your session.
By using dynamic SQL, you can control when the statement is prepared (i.e. parsing the SQL text for syntax (statement formation, keywords, etc.), checked for semantics (object names exist, column names exist, user has required privileges, etc.), and preparing an execution plan.
With the static SQL, all of that happens on the first execution, and then MySQL hangs on to the prepared statement.
For performance reasons, we wouldn't want the overhead of a "hard parse" every time a static statement is executed. This is especially true on a function that gets called multiple times, from a SQL statement.
(NOTE: Oracle does the same thing, BUT, Oracle does a good job of marking prepared statements as INVALID whenever a referenced object is altered or dropped.)
MySQL opted not to do that, probably because of the overhead of tracking all the dependencies. And, in the vast majority of cases, that overhead is not required.
I think the lesson here is if you are going to use dynamic SQL to create a table that is going to have DIFFERENT columns in it, you are going to have to use dynamic SQL to query that table.
My recommendation is that you avoid using SELECT *, unless your statement is in complete control of the columns being returned, for example, from an inline view. Otherwise, SQL statements that use SELECT * are fundamentally broken... they may work now, but a change to a table (adding a column for example) will break an application.
Q: Please explain how it is not a bug.
It is not a bug because the SELECT statement in your stored procedure is really just shorthand for what is actually happening.
On the first execution of your procedure, MySQL is doing the parse of your query text, and preparing and executing a statement. Basically, equivalent to:
PREPARE s1 FROM 'SELECT * FROM mydata';
EXECUTE s1;
On the second execution of the procedure, MySQL is simply executing the statement that has been previously prepared. Basically, equivalent to:
EXECUTE s1;
On that second execution, you seem to be expecting MySQL to run the equivalent of:
DEALLOCATE PREPARE s1;
PREPARE s1 FROM 'SELECT * FROM mydata';
EXECUTE s1;
You can make a case that this is what MySQL should be doing on the second execution. You could argue that statements prepared during a previous execution of a procedure should be discarded, and re-parsed and re-prepared on subsequent executions.
It would not be wrong for a DBMS to do this. But there would be, as always, the consideration about the impact on performance.
You could also make a case that MySQL should track all the database objects that a particular prepared statement is dependent on. You could argue that whenever one of those database objects is dropped or altered, MySQL should invalidate all the prepared statements (and all other objects) that depend on the altered or dropped object. Again, it would not be wrong for a DBMS to do this. Some DBMSs (such as Oracle) do this quite well. But again, the developers of the DBMS also take performance into consideration when making these design and implementation decisions.
The bottom line is that MySQL does provide you with a way to make happen what you want to happen. It's just that the syntax in your procedure, what you are expecting to make it happen, doesn't actually make it happen.
first of all it is a temp table so really should not be expected to be there, 2nd - it is dropped
I think you are reading something different into the "TEMPORARY" keyword than is defined in the specification. A TEMPORARY table is really just like a regular table, except that it is visible only to the session that created it, and it will be automatically dropped when the MySQL session ends. (We also note that a TEMPORARY table is not displayed by a SHOW TABLES command, and does not appear in the information_schema views.)
As to which tables (TEMPORARY or otherwise) MySQL should expect "to be there", I don't believe the documentation really addresses that, except noting that when a SQL statement is executed, and that statement references an object that does not exist, MySQL will throw an exception.
The same behavior you observe with a TEMPORARY table, you will also observe with a non-TEMPORARY table. The issue is not related to whether the table is defined as TEMPORARY or not.
where does SELECT * compare to PREPARE s1 FROM SELECT *
Those two forms effectively follow the same code path. The first execution of a static SELECT * is effectively equivalent to:
PREPARE s1 FROM 'SELECT *';
EXECUTE s1;
(Note the absence of a DEALLOCATE statement following the exeuction.) On a subsequent execution, the statement is already prepared, so it's effectively equivalent to:
EXECUTE s1;
This is similar to what would happen if you were coding in PHP mysqli
$s1 = $mysqli->prepare("SELECT * FROM mydata");
$mysqli->execute($s1);
/* rename the columns in the mydata table */
$mysqli->execute($s1);
I understand this is relatively old (+6 months) but I encountered this problem in prepared statements, and the only way I got around it was to concatenate the field names and use a prepared statement that effectively calls "select *" but uses the actual field names. I'm using prepared statements to create a temporary table, and the only standard field is the first one, while the rest causes the caching problem on "Select *".
Select fields we want to use into a temp table
Iterate through table rows of field names, and on each iteration:
set sql01 = concat(sql01,',',sFieldName,''); (just fields) and: set sql02 = concat(sql02,',',sFieldName,' varchar(50) '); (fields + field type only, for create table statement)
create the output table:
set #sql = concat('CREATE TEMPORARY TABLE tOutput(FirstField varchar(50), ',sql02,');'); PREPARE STMT FROM #sql; EXECUTE STMT; DEALLOCATE PREPARE STMT;
At the end:
set #sql = concat('SELECT FirstField,',sql01,' FROM tOutput;'); PREPARE STMT FROM #sql; EXECUTE STMT; DEALLOCATE PREPARE STMT;
Can I create a new table with an old table's autoincriment status in mysql client?
I think, that ALTER TABLE new_table_name AUTO_INCREMENT=#my_autoincr_iment helps me, but this construction must use with a constant value.
I don't want to use a difficult script.
mysql> create table new_table like old_table;
mysql> select #my_auto_increment:=auto_increment from information_schema.tables where table_name='old_table';
mysql> set #query = CONCAT("alter table new_table auto_increment = ", #my_auto_increment);
mysql> prepare stmt from #query;
mysql> execute stmt;
mysql> deallocate prepare stmt;
Thx to my brother!
Your CREATE TABLE can specify the auto_increment to use:
mysql> create table foo (i int primary key auto_increment, s varchar(12)) auto_increment = 10;
Query OK, 0 rows affected (0.19 sec)
mysql> insert into foo (s) values ("s");
Query OK, 1 row affected (0.09 sec)
mysql> select * from foo;
+----+------+
| i | s |
+----+------+
| 10 | s |
+----+------+
1 row in set (0.03 sec)
I know how to pipe one MySQL query into another:
SELECT user_name FROM users WHERE user_id=( SELECT user_id FROM entries WHERE header="foo" );
Out of pure intellectual curiosity, how I dynamically choose a column or a table?
Ex:
SELECT (
SELECT column_name FROM column_names WHERE id = 1
) FROM (
SELECT table_name FROM table_names WHERE id = 1
);
Use a prepared statement:
mysql> SET #sql = CONCAT("SELECT ", (SELECT "NOW()"));
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #sql;
+--------------+
| #sql |
+--------------+
| SELECT NOW() |
+--------------+
1 row in set (0.00 sec)
mysql> PREPARE stmt FROM #sql;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> EXECUTE stmt;
+---------------------+
| NOW() |
+---------------------+
| 2009-04-06 23:08:31 |
+---------------------+
1 row in set (0.00 sec)
I'm pretty sure this is impossible with a regular query or view.
In answer to your first question, you should learn about how to do JOIN in SQL. A join is a fundamental operation in the SQL language. It's as important is understanding how to do a loop in other languages.
SELECT DISTINCT users.user_name
FROM users JOIN entries USING (user_id)
WHERE entries.header = 'foo';
Regarding your second question, no, you can't make table names or column names dynamic within a single statement.
However, you can write code in your application to build a SQL statement as a string, based on looking up column names and table names. Then execute the resulting string as a new SQL query.
You can do it by querying the information_schema.columns table.
Do this and check the results. I'm not sure what you're trying to do but that table contains anything related to your columns:
SELECT * FROM information_schema.`COLUMNS` C;
BTW, I don't know any way of doing this in a single query. You should get the columns information and then create a new query in your coding language, whatever that is.