PHP and SQLite, INSERT INTO with SELECT doesn't work - php

I am planning to create my website; but to do this, I need to write a CMS...
I've already done most of the work, but now I am getting trouble executing this code. It doesn't return any error, but it simply..doesn't do what it should do.
I have three tables in my database:
users(
id_user primary key,
username unique varchar,
pwd unique varchar,
and more...
)
permissions(
id_permission INTEGER PRIMARY KEY,
permission-name varchar,
and more...
)
permissions_users (
id_permission,
id_user
they are foreign keys that references the same fields of the two previous tables
)
I want that this snippet will check if a checkbox with the same name of the field "permission-name" is checked; if it does, the script should insert into the 3rd table the id_user and id_permission retrieved from the tables permissions and users.
But it doesn't append, even if some checkboxes are checked!
Ah, I am using php 5.3.6, PDO and SQLite 3.7.4. The php code is below...
<?php
$res_perm = $db->query(
"SELECT permission-name FROM permissions"
);
while($result_perm=$res_perm->fetch()) {
if(isset($_POST[$result_perm["permission-name"]])) $db->exec(
"INSERT INTO permissions_users SELECT permissions.id_permission, users.id_user FROM permissions, users WHERE permissions.permission-name = '".$result_perm["permission-name"]."' OR users.nickname = '$ob_nickname'"
) OR die(print_r($db->errorInfo()));
}
?>

I haven't worked too much with SQLLite, but I believe the problem is with permission-name field (there is a dash(minus) sign in it, and I'm pretty sure you have to escape the it (in mysql I'd use backticks)

Related

Storing multiple data in one field (storing data in an array in database)

I have a table called user_thoughts. The table has many columns, one of them being favourited_by.
A thought may be favourited by many different users, but I don't want to create a new row stating that this thought id has been favourited by this user.
I would rather have it that it stores multiple username's in one field. So favourited_by for example can hold data like this:
Alice, Fred, Freddy, Conor ....
All in one single row. I have tried messing around with the data types on phpMyAdmin but cannot figure out how the field can hold multiple data.
What you're asking is the wrong way to do this. You should not serialize the favorites data into a text field for either the user table or the thought table. This destroys the whole purpose of using a relational database like MySQL.
The right way to do this: create a cross-reference table between the user table and the thought table. This utilizes a many-to-many table to store a list of favorites using the primary keys of a thought row and a user row.
Your new favorite table:
CREATE TABLE IF NOT EXISTS `favorite` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`thought_id` int NOT NULL,
PRIMARY KEY (`id`)
);
What this does is take the id from the user table and store it in favorite.user_id, then stores the id from the thought table in favorite.thought_id.
To add a new favorite for the user with the id of 123, for the thought with id 456:
INSERT INTO favorite (user_id, thought_id) VALUES ('123', '456');
Get the users that have marked the thought with id 456 as their favorite (using a JOIN):
SELECT u.* FROM favorite AS f
JOIN user AS u ON u.id = f.user_id
WHERE f.thought_id = 456;
And similar to the last query, get the favorite thoughts for the user with id 123:
SELECT t.* FROM favorite AS f
JOIN thought AS t ON t.id = f.thought_id
WHERE f.user_id = 123;
The ideal way to handle this is to map it to another table, however you can just store it as json.
MySQL 5.7 even includes JSON as a data type allowing easier filtering and manipulation.
https://dev.mysql.com/doc/refman/5.7/en/json.html
You can put json into any text field however if you don't need to search it, etc.

PHP Code for fetching one row in MSSQL in each registration process

Here is my query part of my registration PHP form.
columns account,password,email and age could be inserted by registration page user and they work well but, the column account_id needs to be increased by 1 automatically with each registration process.
Table name is Account not account and column name is account_id.
$query = "INSERT Account( account,password,email,pk_,type_ ) VALUES('$username','$converted_password','$email',1,'$age')";
$query_total = mssql_query("SELECT COUNT(account_id) FROM Account");
$results_check = mssql_query($query_check);
$results_total = mssql_fetch_row($query_total);
$result_total = $results_total['0'];
It gives me a NULL value for the (account_id) column and INSERT fails.
Perform the following query on your database: (Mysql based query!! not Mssql!!)
ALTER TABLE `Account` CHANGE `account_id` `account_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;
this wil result in an autoincrement.
If this fails you'll probably already own duplicates, you'd have to solve this first. There are many ways for this, though it mostly depends upon connections with other tables.
After that for each insert into account do not include the account_id.
use the mysql query:
select LAST_INSERT_ID();
to retrieve the last inserted id.
within PHP you can use http://nl1.php.net/mysql_insert_id though i'd highly advice you to start looking into http://www.php.net/PDO or http://www.php.net/mysqli with prepared statements.
Because as far as i've understood in the next version of PHP the basic Mysql functions will become deprecated. And prepared statements are better/safer. (If properly used)
Set account_id to auto increment in MySQL and just don't shoot anything to the MySQL database for the field account_id. MySQL will automatically create a new ID.
Read something about auto increment:
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
*edit:
Also change
$query = "INSERT Account( account,password,email,pk_,type_ ) VALUES('$username','$converted_password','$email',1,'$age')";
to
$query = "INSERT INTO Account(account,password,email,pk_,type_) VALUES('$username','$converted_password','$email',1,'$age')";

Database normalization and lazy development

I believe the question have emerged as my irritation of doing twice as much work as I could imagine is necessary.
I accept the idea that I could be lacking experience with both MySQL and PHP to think of a simpler solution.
My issue is that I have several tables (and I'd might be adding more) and of these is a parent table, only containing two fields - an id (int) and a name identifying it.
At this moment, I have seven tables with at least 15 fields in each one. Every table has a field, containing the id which I can link to the parent table.
All of these data isn't required to be filled - you will just have to create that one entry in the parent table. For the other tables, I have separate forms.
Now, these forms are made for updating the data in the fields, which means I have to pull out the data from the table if any data is available.
What I would like to do is when I receive the data from my form, I could just use an UPDATE query in my model. But if the table I want to update doesn't have an entry for that specific id, I need to do an insert.
So, my current pseudo code is like this:
$sql = "SELECT id FROM table_x WHERE parent_id = ".$parent_id;
$res = $mysql_query($sql);
if( mysql_num_rows($res) == 1 )
{
$sql = "UPDATE table_x SET ... WHERE parent_id = ".$parent_id;
}
else
{
$sql = "INSERT INTO table_x VALUES ( ... )";
}
mysql_query($sql);
I have two do this for every table I have - can I do something different or smarter or is this just the way it has to be done? Cause this seems very inefficient to me.
Use
INSERT ... ON DUPLICATE KEY UPDATE Syntax
It will insert if record not found,
otherwise, it will update existing record,
and you can skip the check before insert - details
This assuming relation for each 7 table to the parent table is 1:1
Or use REPLACE instead of INSERT - it's an insert, but will do an DELETE and then INSERT when a unique key (such as the primary key) is violated.
in mysql you can do this:
INSERT INTO table
(
col1,
col2
) VALUES(
'val1',
'val2'
) ON DUPLICATE KEY UPDATE table SET
col2 = 'val2'
take a look at the documentation for more information
mysql_query("UPDATE table table_x ..... WHERE parent_id=".$parent_id);
if (mysql_affected_rows()==0) {
mysql_query("INSERT INTO .....");
}

How can I get the foreign keys of a table in mysql

I am creating a class which, takes a table from a database, and displays it to a web-page, with as much functionality as possible. One of the things I would like to support, would be having the class detect which columns in the table have a foreign key constraint on them, so that it can then go to those tables, get all of their values and use them in a select-box which is called when you edit those fields, to avoid someone violating foreign key constraints,
The main problem is discovering which fields have a foreign key constraint on them, and which tables they are pointing to. Does anyone know how to do this???
Thanks,
Lemiant
Simple way to get foreign keys for given table:
SELECT
`column_name`,
`referenced_table_schema` AS foreign_db,
`referenced_table_name` AS foreign_table,
`referenced_column_name` AS foreign_column
FROM
`information_schema`.`KEY_COLUMN_USAGE`
WHERE
`constraint_schema` = SCHEMA()
AND
`table_name` = 'your-table-name-here'
AND
`referenced_column_name` IS NOT NULL
ORDER BY
`column_name`;
The INFORMATION_SCHEMA database contains details of the full schema of all other databases, including constraints:
http://dev.mysql.com/doc/refman/5.0/en/information-schema.html
You can also run a SHOW CREATE TABLE query to get the SQL to create a table, including its constraints.
Much can be retrieved from MySQL's information_schema, foreign keys included, as pointed out by dev-null-dweller.
1
SELECT * FROM information_schema.table_constraints
WHERE table_schema = 'dbname' AND table_name='mytable';
Instead of dbname use the function SCHEMA() to set the name of the database in USE.
2
As pointed out by Dan Grossman, the command
SHOW CREATE TABLE `yourtablename`
can be used basically get an SQL dump of the create table statement.
~3
MySQL provides a SHOW KEYS command. As such you could theoretically get the FK if you know a lower cardinality threshold and have few other keys in the table.
SHOW KEYS FROM `address` WHERE Non_unique AND CARDINALITY > 10000
As the key's cardinality changes each time the internal database is changed, this is rather theoretical. See the cardinality change for instance with running ANALYZE TABLE.
~4
It is useful to stick to a naming schema, such as foreigntablename_foreignfieldname. For example the field user_id in a table billing. Several ORMs of big Web Content Frameworks use this schema.
based on Bill Karwin answer in this other thread, I used this solution to get all the info I needed, included on_delete and on_update rules:
SELECT kcu.referenced_table_schema, kcu.constraint_name, kcu.table_name, kcu.column_name, kcu.referenced_table_name, kcu.referenced_column_name,
rc.update_rule, rc.delete_rule
FROM INFORMATION_SCHEMA.key_column_usage kcu
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc on kcu.constraint_name = rc.constraint_name
WHERE kcu.referenced_table_schema = 'db_name'
AND kcu.referenced_table_name IS NOT NULL
ORDER BY kcu.table_name, kcu.column_name

PHP/MYSQL: SELECT statement, multiple WHERE's, populated from database

I'm trying to figure out how to get a select statement to be populated by an ever-changing number of where's. This is for an order-status tracking application.
Basically, the idea is a user (customer of our company) logs in, and can see his/her orders, check status, etc. No problem. The problem arises when that user needs to be associated with multiple companies. Say they work or own two different companies, or they work for a company that owns multiple sub-companies, each ordering individually, but the big-shot needs to see everything ordered by all of the companies. This is where I'm running into a problem. I can't seem to figure out a good way of making this happen. The only thing I have come up with is this:
client='Client Name One' OR client='Client name two' AND hidden='0' OR client='Client name three' AND hidden='0' OR client='Client name four' AND hidden='0'
(note that client in the previous code refers to the user's company, thus our client)
placed inside of a column called company in my users table of the database. This then gets called like this:
$clientnamequery = "SELECT company FROM mtc_users WHERE username='testing'";
$clientnameresult = mysql_query($clientnamequery); list($clientname)=mysql_fetch_row($clientnameresult);
$query = "SELECT -redacted lots of column names- FROM info WHERE hidden='0' AND $clientname ORDER BY $col $dir";
$result = mysql_query($query);
Thing is, while this works I can't seem to make PHP add in the client=' and ' AND hidden='0' correctly. Plus, it's kind of kludgy.
Any ideas? Thanks in advance!
Expanding on Tim's answer, you can use the IN operator and subqueries:
SELECT *columns* FROM info
WHERE hidden='0' AND client IN
( SELECT company FROM co_members
WHERE username=?
)
ORDER BY ...
Or you can try a join:
SELECT info.* FROM info
JOIN co_members ON info.client = co_members.company
WHERE co_members.username=?
AND hidden='0'
ORDER BY ...
A join is the preferred approach. Among other reasons, it will probably be the most efficient (though you should test this with EXPLAIN SELECT ...). You probably shouldn't grab all table columns (the info.*) in case you can later change the table definition; I only put that in because I didn't know which columns you wanted.
On an unrelated note, look into using prepared queries with either the mysqli or PDO drivers. Prepared queries are more efficient when you execute a query multiple times and also obviate the need to sanitize user input.
The relational approach involves tables like:
CREATE TABLE mtc_users (
username PRIMARY KEY,
-- ... other user info
) ENGINE=InnoDB;
CREATE TABLE companies (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR() NOT NULL,
-- ... other company info
) ENGINE=InnoDB;
CREATE TABLE co_members (
username NOT NULL,
company NOT NULL,
FOREIGN KEY (`username`) REFERENCES mtc_users (`username`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`company`) REFERENCES companies (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE,
INDEX (`username`, `company`)
) ENGINE=InnoDB;
If company names are to be unique, you could use those as a primary key rather than an id field. "co_members" is a poor name, but "employees" and "shareholders" didn't quite seem the correct terms. As you are more familiar with the system, you'll be able to come up with a more appropriate name.
You can use the IN keyword
client IN('client1','client2',...)

Categories