mysql only insert row if value does not exists [duplicate] - mysql
This question already has answers here:
MySQL Conditional Insert
(13 answers)
Closed 8 years ago.
A complex mysql question! I only want to insert the last value (with the zero values) if there is no other row with value 1420070400, but i cant put an index on the row (so i can use on duplicate key). Is there a way to do this on an other way?
INSERT INTO data_prijzen_advertentie (
`ID_advertentie`,`jaar`,`rijnr`,`status_prijs`,`datum_dag`,`timestamp_dag`,
`prijs_maand`,`prijs_week`,`prijs_midweek`,`prijs_langweekend`,`prijs_weekend`,
`prijs_dag`,`prijs_ochtend`,`prijs_middag`
)
VALUES
(100,2014,1,1,'12-05-2014',1399852800,0,100,0,75,0,0,0,0),
(100,2014,2,1,'23-05-2014',1400803200,0,75,0,101,0,0,0,0),
(100,2014,3,1,'30-05-2014',1401408000,0,100,0,75,0,0,0,0),
(100,2014,4,1,'01-01-2015',1420070400,0,0,0,0,0,0,0,0)
ON DUPLICATE KEY UPDATE
status_prijs = VALUES(status_prijs), datum_dag = VALUES(datum_dag),
timestamp_dag = VALUES(timestamp_dag), prijs_maand = VALUES(prijs_maand),
prijs_week = VALUES(prijs_week), prijs_midweek = VALUES(prijs_midweek),
prijs_langweekend = VALUES(prijs_langweekend), prijs_weekend = VALUES(prijs_weekend),
prijs_dag = VALUES(prijs_dag), prijs_ochtend = VALUES(prijs_ochtend),
prijs_middag = VALUES(prijs_middag);
One way to do this is to use a SELECT in place of the VALUES clause. Use the SELECT statement to return the rows you want inserted. For example:
SELECT 100 AS a,2014 AS b,1 AS c,1 AS d,'12-05-2014' AS e
,1399852800 AS timestamp_dag
,0 AS g,100 AS h,0 AS i,75 AS j,0 AS k,0 AS l,0 AS m,0 AS n
UNION ALL
SELECT 100,2014,2,1,'23-05-2014',1400803200,0,75,0,101,0,0,0,0
UNION ALL
SELECT 100,2014,3,1,'30-05-2014',1401408000,0,100,0,75,0,0,0,0
UNION ALL
SELECT 100,2014,4,1,'01-01-2015',1420070400,0,0,0,0,0,0,0,0
With a SELECT, it's also possible to check for rows that already exist in the table. You can use that query above as an inline view (i.e. wrap that query in parens and assign an alias for the derived table) and write a SELECT against it (like it was a table), and use a NOT EXISTS predicate or an anti-join pattern to suppress the return of rows where a "matching" row already exists in the target table. For example:
SELECT s.*
FROM ( SELECT 100 AS a,2014 AS b,1 AS c,1 AS d,'12-05-2014' AS e
,1399852800 AS timestamp_dag
,0 AS g,100 AS h,0 AS i,75 AS j,0 AS k,0 AS l,0 AS m,0 AS n
UNION ALL
SELECT 100,2014,2,1,'23-05-2014',1400803200,0,75,0,101,0,0,0,0
UNION ALL
SELECT 100,2014,3,1,'30-05-2014',1401408000,0,100,0,75,0,0,0,0
UNION ALL
SELECT 100,2014,4,1,'01-01-2015',1420070400,0,0,0,0,0,0,0,0
) s
LEFT
JOIN data_prijzen_advertentie t
ON t.timestamp_dag = s.timestamp_dag
WHERE t.timestamp_dag IS NULL
(NOTE: the LEFT JOIN operation returns all rows from the derived table s, along with matching rows from t; the "trick" is to use a WHERE clause that eliminates all rows that found a match, so we are left with rows from s that didn't have a matching row in t. The same thing could be achieved with a NOT EXISTS predicate with a correlated subquery.)
It may be necessary to wrap this query in parens and reference it as an inline view (so it is again, a derived table) to avoid a mutating table issue/error. For example:
SELECT r.*
FROM (
SELECT s.*
FROM (
SELECT 100 AS a,2014 AS b,1 AS c,1 AS d,'12-05-2014' AS e
,1399852800 AS timestamp_dag
,0 AS g,100 AS h,0 AS i,75 AS j,0 AS k,0 AS l,0 AS m,0 AS n
UNION ALL
SELECT 100,2014,2,1,'23-05-2014',1400803200,0,75,0,101,0,0,0,0
UNION ALL
SELECT 100,2014,3,1,'30-05-2014',1401408000,0,100,0,75,0,0,0,0
UNION ALL
SELECT 100,2014,4,1,'01-01-2015',1420070400,0,0,0,0,0,0,0,0
) s
LEFT
JOIN data_prijzen_advertentie t
ON t.timestamp_dag = s.timestamp_dag
WHERE t.timestamp_dag IS NULL
) r
Once you have a query working that returns the rows you want (excluding rows where a matching row already exists in the target table), you can substitute the VALUES clause in the INSERT statement with the query.
Note: this only checks for existence of rows already in the table when the query runs. This doesn't check the resultset returned by the query, to see if there are two (or more) rows with the timestamp_dag value.
Related
Select IN with an array with duplicate value on it
I am trying to make a request where I select from an array of value using the IN, but inside this array, if I have the same value twice, I'd like the request to return the result twice. To clarify, here is an example: select id_exo, count(id_exo) FROM BLOC WHERE id_seance IN (10,10) group by id_exo So inside the IN, I put 2 times the value 10. Here is the result: id_exo count(id_exo) 60 1 82 1 But in count, I'd like to have the number 2 since I have put twice 10 inside my IN. How can I achieve that?
SELECT id_exo, COUNT(id_exo) FROM bloc JOIN (SELECT 10 id_seance UNION ALL SELECT 10) val USING (id_seance) GROUP BY id_exo
Prior to MySQL 8.0 you can join with a sub select: select * from BLOC as b inner join ( select 1 as 'id', 10 as 'value' union select 2,10 union select 3,10) as myValues on myValues.value = b.id_seance You need the id column as the UNION statement removes duplicate rows If you are lucky enough to have MySQL 8.0 look at the VALUES statement https://dev.mysql.com/doc/refman/8.0/en/values.html Here you should instead be able to join with something like VALUES ROW(10), ROW(10), ROW(10)
How to find which values are not in a column from the list?(SQL) [duplicate]
This question already has an answer here: Select values from a list that are not in a table (1 answer) Closed 2 years ago. I have a list of values: ('WEQ7EW', 'QWE7YB', 'FRERH4', 'FEY4B', .....) and the dist table with a dist_name column. and I need to create SQL query which would return values from the list which don't exist in the dist_name column.
Yo need to use left join. This requires creating a derived table with the values you care about. Here is typical syntax: select v.val from (values ('WEQ7EW'), ('QWE7YB'), ('FRERH4'), ('FEY4B') ) v(val) left join t on t.col = v.val where t.col is null; Not all databases support the values() table constructor but allow allow some method for creating a derived table. In MySQL, this looks like: select v.val from (select'WEQ7EW' as val union all select 'QWE7YB' as val union all select 'FRERH4' as val union all select 'FEY4B' as val ) v(val) left join t on t.col = v.val where t.col is null;
You would typically put this list of values in a derived table, and then use not exists. In MySQL: select v.dist_name from ( select 'WEQ7EW' as dist_name union all select 'QWE7YB' union all ... ) v where not exists (select 1 from dist d where d.dist_name = v.dist_name) Or if you are running a very recent version (8.0.19 or higher), you can use the VALUES ROW() syntax: select v.dist_name from (values row('WEQ7EW'), row('QWE7YB'), ...) v(dist_name) where not exists (select 1 from dist d where d.dist_name = v.dist_name)
SELECT TRIM(TRAILING ',' FROM result) result FROM ( SELECT #tmp:=REPLACE(#tmp, CONCAT(words.word, ','), '') result FROM words, (SELECT #tmp:='WEQ7EW,QWE7YB,FRERH4,FEY4B,') arg ) perform ORDER BY LENGTH(result) LIMIT 1; fiddle The list of values to be cleared from existing values is provided as CSV string with final comma and without spaces before/after commas ('WEQ7EW,QWE7YB,FRERH4,FEY4B,' in shown code). If CSV contains duplicate values all of them will be removed whereas non-removed duplicates won't be compacted. The relative arrangement of the values will stay unchanged. Remember that this query performs full table scan, so it is not applicable to huge tables because it will be slow.
Sql select where array in column
In my query I use join table category_attributes. Let's assume we have such rows: category_id|attribute_id 1|1 1|2 1|3 I want to have the query which suites the two following needs. I have a variable (php) of allowed attribute_id's. If the array is subset of attribute_id then category_id should be selected, if not - no results. First case: select * from category_attributes where (1,2,3,4) in category_attributes.attribute_id should give no results. Second case select * from category_attributes where (1,2,3) in category_attributes.attribute_id should give all three rows (see dummy rows at the beginning). So I would like to have reverse side of what standard SQL in does.
Solution Step 1: Group the data by the field you want to check. Step 2: Left join the list of required values with the records obtained in the previous step. Step 3: Now we have a list with required values and corresponding values from the table. The second column will be equal to required value if it exist in the table and NULL otherwise. Count null values in the right column. If it is equal to 0, then it means table contains all the required values. In that case return all records from the table. Otherwise there must be at least one required value is missing in the table. So, return no records. Sample Table "Data": Required values: 10, 20, 50 Query: SELECT * FROM Data WHERE (SELECT Count(*) FROM (SELECT D.value FROM (SELECT 10 AS value UNION SELECT 20 AS value UNION SELECT 50 AS value) T LEFT JOIN (SELECT value FROM Data GROUP BY value) D ON ( T.value = D.value )) J WHERE value IS NULL) = 0;
You can use group by and having: select ca.category_id from category_attributes ca where ca.attribute_id in (1, 2, 3, 4) group by ca.category_id having count(*) = 4; -- "4" is the size of the list This assumes that the table has no duplicates (which is typical for attribute mapping tables). If that is a possibility, use: having count(distinct ca.attribute_id) = 4
You can aggregate attribute_id into array and compare two array from php. SELECT category_id FROM (select category_id, group_concat(attribute_id) as attributes from category_attributes order by attribute_id) t WHERE t.attributes = (1, 2, 3); But you need to find another way to compare arrays or make sure that array is always sorted.
MYSQL The used SELECT statements have a different number of columns
I need to combined 2 tables with the same ids in it but i can't SELECT stat.user_id, user.username, SUM(stat.vertrag) AS vertrag, SUM(stat.zubehoer) AS zubehoer, SUM(stat.privat) AS privat, SUM(stat.service) AS service, SUM(stat.bs_vertrag) AS bus FROM statistics stat join users user on stat.user_id = user.uid WHERE stat.user_id != '0' AND stat.datum LIKE '%$month%' GROUP BY stat.user_id UNION SELECT bew.user_id, stat.user_id, user.username, SUM(case when bew.log = 'inv_imei' THEN 1 ELSE 0 END) AS inv FROM user_bewegungen bew JOIN users user ON user.uid = bew.user_id JOIN statistics stat ON bew.user_id = stat.user_id WHERE bew.date LIKE '%$month%' GROUP BY bew.user_id ORDER BY vertrag DESC I am dont know how to go now..... The first select is perfect, and works. now i have add a union because i need to add the row "log". Id's are also in it but i become the error The used SELECT statements have a different number of columns Can anyone help?
Each select statement needs to have the same number of columns. Your first one has 7: SELECT stat.user_id, user.username, SUM(stat.vertrag) AS vertrag, SUM(stat.zubehoer) AS zubehoer, SUM(stat.privat) AS privat, SUM(stat.service) AS service, SUM(stat.bs_vertrag) AS bus Your second one has 4: SELECT bew.user_id, stat.user_id, user.username, SUM(case when bew.log = 'inv_imei' THEN 1 ELSE 0 END) AS inv You can select NULL in the second SELECT for those columns that aren't in the first one.
Make the two operands of the UNION isomorphic. Rename columns and/or create NULL-valued dummy columns as necessary to give them the same shape. FOR EXAMPLE, if we wanted to form the UNION of: SELECT a, b, c FROM table1 and: SELECT d, e FROM table2 we would logically pair those columns that are of the same types (in this case, let's assume that a and e are of the same type, and that b and d are of the same type) and add an extra NULL-valued column as the third projected attribute of the right-hand SELECT, as follows: SELECT b, a, c FROM table1 UNION SELECT d AS b, e AS a, NULL as c FROM table2 If such an approach seems confusing, you can use table views to simplify the expression. In the preceding example, you could have asserted a view atop table2: CREATE VIEW t2view( b, a, c ) AS SELECT d, e, NULL FROM table2 and then formulated your UNION as: SELECT b, a, c FROM table1 UNION SELECT * FROM t2view
In UNION, the field numbers should be the same. Use like this: SELECT stat.user_id, 0, user.username, .... SELECT bew.user_id, stat.user_id, user.username, ... or use something else, what you know, that is a missing field there. The data types should be the same also.
You are using MySQL Union. UNION is used to combine the result from multiple SELECT statements into a single result set. The column names from the first SELECT statement are used as the column names for the results returned. Selected columns listed in corresponding positions of each SELECT statement should have the same data type. (For example, the first column selected by the first statement should have the same type as the first column selected by the other statements.) Reference: MySQL Union Your first select statement has 7 columns and second statement has 4. You should have same number of column and also in same order in both statement. otherwise it shows error or wrong data.
you can see this example there are two queries both queries have the same number of columns. column name can be different. select 'row1' as column1,'row2' as column2 union select 'row3' as column11,'row4' as column222 if you change columns count, it means in first query you are selecting 2 columns and in second query you are using 3 columns then it will through an error (The used SELECT statements have a different number of columns). select 'row1' as column1,'row2' as column2 union select 'row3' as column11,'row4' as column222 ,'rr' as t ; run both queries you will see differnce.
mysql query return null row [duplicate]
This question already has answers here: SELECT SUM returns a row when there are no records (8 answers) Closed 7 years ago. i want to execute this query but it return null row when the table empty. it's working when SUM(products.sale_price)/COUNT(orders.id) AS avg_price_rang is not in the query SELECT products.brand_id, (SELECT category_brands.name FROM category_brands WHERE category_brands.id=products.brand_id ) AS brand, products.material_id, (SELECT category_materials.material FROM category_materials WHERE category_materials.id=products.material_id ) AS material, orders.color_code, SUM(products.sale_price)/COUNT(orders.id) AS avg_price_rang FROM orders INNER JOIN products ON orders.prodcut_id = products.id
I think it's missing GROUP BY products.brand_id.
SELECTing SUM when there are no rows causess a row of all NULLs to be returned. MySQL 5.5 Reference Manual 12.17.1 GROUP BY (Aggregate) Functions If you use a group function in a statement containing no GROUP BY clause, it is equivalent to grouping on all rows. For more information, see Section 12.17.3, “MySQL Handling of GROUP BY”. Use: query HAVING avg_price_rang IS NOT NULL SELECT * FROM ( query ) dummy WHERE avg_price_rang IS NOT NULL