Insert distinct values only for one column - php

Say, I have a table with five columns col1, col2, col3, col4 and user_id. Now, I have an array of user_id values, say a thousand. I want to insert thousand of records where only distinct column value is user_id. If there is a simplier way rather than make a thousand of ('col1value','col2value','col3value','col4value',someUserId) and concatenate them in single insert into tbl (col1,col2,col3,col4,user_id) values query?
Update: I guess it needs some clarification
So here's simple example. Let's say I have an events table with fields event and user_id. Some call event occurs for users with id 1, 2, 5, 101, 233, 422 and 1000. So I need to insert 7 records into table so it should look like
+-------+---------+
| event | user_id |
|-------|---------|
| call | 1 |
| call | 2 |
| call | 5 |
| call | 101 |
| call | 233 |
| call | 422 |
| call | 1000 |
+-------+---------+
I want to do it as efficiently database-wise as possible. So far, I think I have to make such SQL query:
insert into events (event,user_id) values ('call',1),('call',2),('call',5),('call',101),('call',233),('call',422),('call',1000);
then perform a single query
But maybe there is some more simple and efficient way? Maybe something with SQL parameters or such?

I understand your question that you have a high number of different user_id values that you want to insert, but for each new record you want the same values for col1, col2, col3 and col4.
The easiest way to achieve this would be to set a DEFAULT value for each of the columns:
ALTER TABLE mytable CHANGE `col1` `col1` INTEGER NOT NULL DEFAULT 1234
This sets the default value for col1 to 1234. I assumed the column to be of data type INTEGER, you need to change it accordingly.
If changing the table is not an option for you, then you could still build an insert statement that would insert all records in a single transaction:
$user_ids = array(5,6, 7, 8, 9, 10); // these are the user ids you want to insert
$default_vals = array(1, 2, 3, 4); // These are the default values used for col1, col2, col3 and col4
$con = new mysqli('mydomain', 'myuser', 'mypw', 'mydb');
$rows = array();
foreach ($user_ids as $id)
$rows[] = "(".implode(',', $default_vals).",$id)";
$sql = "INSERT INTO mytbl (col1, col2, col3, col4, id) VALUES " . implode(',', $rows) . ";";
$con->query($sql);
Or, if for academic reason you'd rather write a single INSERT statement to do the whole job, you could write:
INSERT INTO mytbl (col1, col2, col3, col4, id)
SELECT * FROM
(SELECT 1, 2, 3, 4) AS DEFAULT_VALS,
(SELECT 5
UNION SELECT 6
UNION SELECT 7
UNION SELECT 8
UNION SELECT 9) AS USER_IDS
However, the last approach really isn't very nice. Neither in terms of readability nor of performance.
Edit
I made a quick benchmark for you:
Inserting 10k different records like in my PHP sample took 1.5086660385132 seconds on my webserver.
The SELECT INTO approach with 10k UNIONs took 3.3481941223145 seconds.
Easy choice, though.

Use :
INSERT INTO tbl (col1,col2,col3,col4,user_id)
VALUES
(1,2,3,4,1000),
(2,3,4,5,1000),
(6,7,8,9,1000),
(1,2,3,4,1234),
(4,3,2,1,1235);

Create unique index on user_id field. use INSERT IGNORE or INSERT ... ON DUPLICATE KEY UPDATE for ignoring duplicate insertion of user_id.
For details, kindly refer MySQL documentation.
http://dev.mysql.com/doc/refman/5.6/en/insert.html

Related

On Duplicate of entire rows of same values how to increase count?

I have a table using php mysql and using pdo for fetching records.
I want to know sql query so that if I insert row of all same values of same fields(duplicate row). It should insert new row by upgarding the count which is also one of the field
INSERT INTO table_name (column1, column2, column3, column4)
VALUES (value1, value2, value3,values4)
ON DUPLICATE KEY UPDATE count = count + 1;
this is hypothetical example
column2 is an id, which is foreign key constraints of another table2,
column3 is an id, which is foreign key constraints of another table3,
column4 is an id, which is foreign key constraints of another table4
total 4 tables I have. My table looks like this
Sno | column2_id | column3_id | count | column4_id
1 | column2_value | column3_value | 1 | column4_value
I have fetched all three tables data through id and show in table 1.
I have different values only 5 id in table 2 which have corresponding values.
if I insert new row of duplicate values it should insert by increasing count values.
By default I have taken count as 1.
I didn't understand very well your request.
But if I understand correctly you want to update a row if it is duplicate?
If so you can just use an ON DUPLICATE KEY UPDATE
For example :
INSERT INTO table_name (column1, column2, column3, number)
VALUES (value1, value2, value3, number)
ON DUPLICATE KEY UPDATE number = number + 1;

Get LAST_INSERT_ID() from a multi-insert in MySQL

I need to get my id value after inserting multiply rows in my MySQL database
INSERT INTO table (`row1`, `row2`, `row3`, `row4`)
VALUES
('value1','value2','value3','value4'),
('value1','value2','value3','value4');
in the fact I need to something like
SQL Server - Return value after INSERT
but for MySQL and I don't need to return last id because I can do it by myself but I thought it is not good for what I doing
is any better way exist for my question?
If you want to insert blocks of rows into the parent and child table, your rows must have unique columns so you can look up the parent rows after insert:
INSERT INTO table (col1, col2, col3, col4)
VALUES
('value1','value2','value3','value4'),
('value5','value6','value7','value8');
INSERT INTO childtable (colx, coly, id_table)
SELECT 1, 2, id FROM table WHERE col1 = 'value1' and col2 = 'value2' and col3 = 'value3' and col4 = 'value4'
UNION ALL
SELECT 1, 2, id FROM table WHERE col1 = 'value5' and col2 = 'value2' and col3 = 'value3' and col4 = 'value4'
Even if there was a method for getting all inserted IDs, you'd have to do the same thing, because tables contain an unordered set of rows. If you got back IDs 11 and 12 for the first insert statement, which row would ID 11 refer to and which ID 12? There is no way to tell that, because the DBMS is free to insert the rows in any order.
If the row data is not unique as in your example, where both rows contain ('value1','value2','value3','value4'), then you must either insert all the data in a loop or use some CTE to number the rows first and play with those numbers.
Anyway, having said all that, I would just insert the data row by row in a loop (i.e. one parent, all its children, next parent, ...), as long as you don't get unbearable performance issues.

Applying WHERE clause when doing a UNION

I am struggling to get this MySQL query to work. I have two tables:
Table 1
TYPE | NAME | LAT | LON | ICON
Table 2
ID | UID | NAME | LAT | LON | ICON
I am trying to select all results from Table 1 and only select some results from Table 2. I am trying to apply a WHERE clause to Table 2 but it doesn't seem to work.
I read the documentation and it said for a UNION to work the number of columns have to be the same. How can I then only select the same number of columns from both tables to be returned but filter the second table by a column only found on that table?
My (pseudo)Query:
(SELECT name,lat,lon,icon
FROM Table1)
UNION
(SELECT name,lat,lon,icon
FROM Table2
WHERE uid ="1")
SELECT * FROM table1
UNION
SELECT
NULL AS `type`,
`name`,
`lat`,
`long`,
`icon`
FROM table2 WHERE uid = 1
http://www.sqlfiddle.com/#!9/0a942/8
This selects everything from table1, and only where uid = 1 from table2.
An UNION can only be performed if both row sets have the exact same columns. Since there is no type column in table2, we select a NULL and name it type so we can do the UNION.

Mysql query "WHERE 2 IN (`column`)" not working

I want to execute a query where I can find one ID in a list of ID.
table user
id_user | name | id_site
-------------------------
1 | james | 1, 2, 3
1 | brad | 1, 3
1 | suko | 4, 5
and my query (doesn't work)
SELECT * FROM `user` WHERE 3 IN (`id_site`)
This query work (but doesn't do the job)
SELECT * FROM `user` WHERE 3 IN (1, 2, 3, 4, 6)
That's not how IN works. I can't be bothered to explain why, just read the docs
Try this:
SELECT * FROM `user` WHERE FIND_IN_SET(3,`id_site`)
Note that this requires your data to be 1,2,3, 1,3 and 4,5 (ie no spaces). If this is not an option, try:
SELECT * FROM `user` WHERE FIND_IN_SET(3,REPLACE(`id_site`,' ',''))
Alternatively, consider restructuring your database. Namely:
CREATE TABLE `user_site_links` (
`id_user` INT UNSIGNED NOT NULL,
`id_site` INT UNSIGNED NOT NULL,
PRIMARY KEY (`user_id`,`site_id`)
);
INSERT INTO `user_site_links` VALUES
(1,1), (1,2), (1,3),
(2,1), (2,3),
(3,4), (3,5);
SELECT * FROM `user` JOIN `user_site_links` USING (`id_user`) WHERE `id_site` = 3;
Try this: FIND_IN_SET(str,strlist)
NO! For relation databases
Your table doesn't comfort first normal form ("each attribute contains only atomic values, and the value of each attribute contains only a single value from that domain") of a database and you:
use string field to contain numbers
store multiple values in one field
To work with field like this you would have to use FIND_IN_SET() or store data like ,1,2,3, (note colons or semicolons or other separator in the beginning and in the end) and use LIKE "%,7,%" to work in every case. This way it's not possible to use indexes[1][2].
Use relation table to do this:
CREATE TABLE user_on_sites(
user_id INT,
site_id INT,
PRIMARY KEY (user_id, site_id),
INDEX (user_id),
INDEX (site_id)
);
And join tables:
SELECT u.id, u.name, uos.site_id
FROM user_on_sites AS uos
INNER JOIN user AS u ON uos.user_id = user.id
WHERE uos.site_id = 3;
This way you can search efficiently using indexes.
The problem is that you are searching within several lists.
You need something more like:
SELECT * FROM `user` WHERE id_site LIKE '%3%';
However, that will also select 33, 333 and 345 so you want some more advanced text parsing.
The WHERE IN clause is useful to replace many OR conditions.
For exemple
SELECT * FROM `user` WHERE id IN (1,2,3,4)
is cleaner than
SELECT * FROM `user` WHERE id=1 OR id=2 OR id=3 OR id=4
You're just trying to use it in a wrong way.
Correct way :
WHERE `field` IN (list_item1, list_item2 [, list_itemX])

Mysql SELECT with an OR across 2 columns

I'm creating a 'similar items' link table.
i have a 2 column table. both columns contains product ids.
CREATE TABLE IF NOT EXISTS `prod_similar` (
`id_a` int(11) NOT NULL,
`id_b` int(11) NOT NULL
)
INSERT INTO `prod_similar` (`id_a`, `id_b`) VALUES
(5, 10),
(5, 15),
(10, 13),
(10, 14),
(14, 5),
(14, 13);
I want to select 3 similar products, favouring products where the id is in the first col, 'id_a'
SELECT * FROM prod_similar WHERE id_a={$id} OR id_b={$id}
ORDER BY column(?)
LIMIT 3
Don't know, maybe this?
SELECT *
FROM similar_items
WHERE col_1={$id} OR col_2={$id}
ORDER BY CASE WHEN col_1={$id} THEN 0 WHEN col_2={$id} THEN 1 END
LIMIT 3
I assume you have other columns as well
(SELECT 1 favouring, id_a id, [other columns]
FROM prod_similar
WHERE id_a = {$id})
UNION
(SELECT 2 favouring, id_b id, [other columns]
FROM prod_similar
WHERE id_b = {$id})
ORDER BY favouring, id
LIMIT 3;
In case you don't mind duplicates or there are none between id_a and id_b you can do UNION ALL instead which is considerably faster.
Unions are indication of denormalized data, denormalized data improves speed of certain queries and reduces speed of others (such as this).
An easy way to do this is this:
ORDER BY NULLIF(col_1, {$id}) LIMIT 3
The CASE WHEN works as well, but this is bit simpler.
I am not sure I get the question, could you maybe post example data for the source table and also show what the result should look like.
If I got you right i would try something like
Select (case
when col_1={$ID}:
col1
when col_2={$ID}:
col2) as id from similar_items WHERE col_1={$id} OR col_2={$id}
LIMIT 3

Categories