SQL INSERT INTO xxx WHERE NOT EXIST - mysql

I am trying to insert into a table, but only if unique. I can do this on one criteria, but not two? I am not sure where I am going wrong? It doesn't return an error, just behaves as if there is only one criteria.
Simple table, autoID, status, type
INSERT INTO alarms (status, type)
SELECT * FROM (SELECT '2', '1') AS tmp
WHERE NOT EXISTS
( SELECT type FROM alarms WHERE (type = '1')) LIMIT 1;
This works fine, it will only insert if there are no other entries with a type of 1.
I would like to have multiple criteria, ie if already in the table type=1 AND status=5 then insert a new entry of type=1 and status=2. I have tried the following (with a few variations) but cannot get it to work. No errors, just behaves as if there is only one criteria.
INSERT INTO alarms (status, type)
SELECT * FROM (SELECT '2', '1') AS tmp
WHERE NOT EXISTS
( SELECT type, status FROM alarms WHERE (type = '1' AND status = '5')) LIMIT 1;
Any advice? Or do I need to do a separate call to determine the multiple criteria existence.
Thanks.

Have you tries using if-begin-end instead?
The code might be simpler but, this still count as a single statement I suppose.
If Not Exists( SELECT type, status FROM alarms WHERE (type = '1' AND status = '5'))
Begin
INSERT INTO alarms (status, type) values ("Y","type")
End

Try using "HAVING"
INSERT INTO alarms (status, type)
SELECT status, type
FROM alarms_duplicated AS a
WHERE status = '2' AND type = '1'
GROUP BY status, type
HAVING COUNT(*) = 1

thanks for your input.
I would look as if the IF NOT EXIST.... WHERE will not work, apparently the WHERE statement is not compatible with mySQL. So I did it a different way!
(Entirely different approach to the issue at hand, not relative to this discussion).

Related

Case in list - Tableau

I'm trying to filter out a huge amount of data out so i decided to create a calculated field and using case if product_id in the list then '1' else '0'
but for some reason it though syntax error.
this is my calculated field:
CASE when product_id in (
'31049','31048','26166','27816','26031','28861','28864','28863','28203','28110','20641','38112','45174','20645','28404','20646','20648','26159','33287','31417','40551','41020','40550','40550','40553','40554','29804','29941','31430','33354','36730','26073','31432','31433','31431','38154','38166','26029','28341','45138','38069','42069','26060','26060','33886','33886','28392','29518','44879','20651','20655','42914','37535','28031','27588','29297','37688','37709','29551','29551','30183','29550','26187','29549','41348') THEN '1' ELSE '0'
END
Any idea who it should be written?
Thanx in advance :)
On a sample dataset this works:
SELECT RIDE_ID as ri,
CASE
WHEN ri in ('5EB0FAD625CFAEAB', '5A9314E3AF8DCC30') THEN '1'
ELSE '0'
END AS result
FROM CITIBIKE_TRIPS LIMIT 10;
I get:
yes it works in the database but not in Tableau :) I couldn't run it in a calculated field
Maybe using LATERAL would allow to run it from Tableau:
CREATE OR REPLACE TABLE t(ID INT, product_id TEXT);
INSERT INTO t VALUES (1, '31049'),(2,'31048'), (3, '100');
SELECT *
FROM t
,LATERAL (SELECT CASE WHEN t.product_id IN ( '31049','31048','26166','27816'/*...*/)
THEN '1' ELSE '0' END) AS s(result);
One option— create a table with your keys that you wish to filter, and then use a join to let the database do the work. Could be easier to maintain. Likely more efficient
Another option is to create a set in Tableau based on the product_id field. Define that set by checking the product ids you wish, and then place the set of the filter shelf to filter to either include or exclude the product_ids in your set.

Select id from input list NOT present in database

With MySql vers 8.0:
CREATE TABLE cnacs(cid VARCHAR(20), PRIMARY KEY(cid));
Then,
INSERT INTO cnacs VALUES('1');
The first two statements execute successfully. The next statement does not, however. My goal is to return a list of unused cid's from the input table [1, 2]:
SELECT * FROM (VALUES ('1'),('2')) as T(cid) EXCEPT SELECT cid FROM cnacs;
In theory, I'd like the output to be '2', since it has not yet been added. The aforementioned query was inspired by Remus's answer on https://dba.stackexchange.com/questions/37627/identifying-which-values-do-not-match-a-table-row
This is at least the correct syntax for what you are trying to do.
If this query is anything more than a learning exercise though I'd rethink the approach, storing these '1' and '2' values (or however many there ends up being) in their own table
SELECT Column_0
FROM (SELECT * FROM (VALUES ROW('1'), ROW('2')) TMP) VALS
LEFT
JOIN cnacs
ON VALS.Column_0 = cnacs.cid
WHERE cnacs.cid IS NULL

Mysql query insert into only if select count > n

I have 2 queries:
SELECT COUNT(*) FROM a WHERE id = 1
//if row == 1
INSERT INTO a VALUES(fielda) VALUES('value')
Is there a way to merge these two queries into one? I tried with 'IF (count> 0, ..)' and similar, but the query is incorrect.
This involves inserting a new record into the table, taking care not to exceed a pre-set number of records for each field.
In theory it should be similar to an INSERT IF ...
Edit:
#Barmar I tried but I think I did not understand what you wrote (in fact I made a mistake in the query), I try to answer like this:
THE QUERY AFTER YOUR RESPONSE:
INSERT INTO table1 SELECT MAX(id) FROM table1 WHERE field1 = (SELECT id from a WHERE f = field2) HAVING COUNT(*) = 1 (all fields request) VALUES (all values request)
//field1 = id from table2
//field2 = id from another table: associative value
//ORIGINAL QUERY
//FIRST COUNT:
SELECT COUNT(*) from table1 WHERE field1 = (SELECT id FROM table2 WHERE f = field2)
//AFTER THE INSERT:
INSERT INTO table1 (all fields request) VALUES (all values request)
I came to mind this example I try to show you:
TABLE PLAYER: fields(ID, TEAMID, NAME) => (id=int, teamid=int associate to table team, name=varchar)
TABLE TEAM: fields(ID NAME) => (id=int, name=varchar)
Suppose that the players in a team are maximum 20, so you expect maximum 20 records associated by the player table for the same teamid value, or at least this is what we humans think, because for the computer can also be infinite. I was looking for a way to allow the insertion only in the case in which it is actually permissible to insert records, in this case the condition is that in the players table there are less than 21 records per team.
You can use INSERT ... SELECT, and put the condition in the SELECT query.
INSERT INTO player (teamid, name)
SELECT #teamid, #playername
FROM DUAL
WHERE (SELECT COUNT(*) FROM player
WHERE teamid = #teamid) < 20
DUAL is a dummy table when you need to select literal data, but need to include other clauses in the query.

Mysql insert record if / where sum of fields + var <= value in a field (laravel)

First question ever on stack, I really couldn't find the answer elsewhere
I am making a ticket reservation system and I would like one query to create a ticketsorder if the total of ordered tickets after this call would be equal or smaller than the maxtickets value of tickettype and the maxticketstype of the event.
I have 3 tables
events with columns id, maxtickets
tickettypes with columns id, event_id, maxtickets
ticketsorders with columns id, tickettype_id, amount (amount is number of tickets)
The reason I want to do it in 1 call is so that there can never be more tickets ordered than the specified maximum on the ticketype or the event. If I would get the two sums in php and than write if my php calculations are okay there will be time between the getting of sums and writing the new value and possibly there will be more tickets ordered than allowed.
Maybe I'm looking for the wrong solution and maybe I should do more homework, any direction is appreciated, a fully working query would be most awesome :)
I mentioned laravel because it uses eloquent databases queries but I can use raw SQL when I want so no problem if the solution is raw SQL.
Thank you in advance!
Update: (Got it working with help from mentioned question)
INSERT into ticketsorders (order_id, tickettype_id, event_id, amount)
SELECT '7', '23', '1', '10'
FROM dual
WHERE ((SELECT COALESCE(SUM(amount), 0) FROM ticketsorders WHERE tickettype_id = 23) + '10' ) <= (SELECT maxtickets from tickettypes where id = '23')
AND ((SELECT COALESCE(SUM(amount), 0) FROM ticketsorders WHERE event_id = 1) + '10' ) <= (SELECT maxtickets from events where id = '1')
LIMIT 1
only uglieness I had to add was event_id to ticketsorders, we learned in school that you shouldnt do this because its available throug relation event->tickettype->ticketsorder but for now this makes quering for event objects alot easier.
Final update concerning laravel:
after adding in the vars and wrapping the sql in a raw statement like this:
$sql = "INSERT into ticketsorders (order_id, tickettype_id, event_id, amount) SELECT $order->id, $tickettype->id, $eventid, $val FROM dual WHERE ((SELECT COALESCE(SUM(amount), 0) FROM ticketsorders WHERE tickettype_id = $tickettype->id) + $val ) <= (SELECT max from tickettypes where id = $tickettype->id) AND ((SELECT COALESCE(SUM(amount), 0) FROM ticketsorders WHERE event_id = $eventid) + $val ) <= (SELECT max from events where id = $eventid) LIMIT 1";
$testupdate = DB::insert(DB::raw("$sql"));
I found out that the query always returns 1 which means true, even if the insert doesn't go through because the query still ran successfully. Rather than breaking my head on this issue trying to get the actual result I decided to do a new select and see if it succeeded and base my return message to the user on the intended insert compared to the select.
Thank you for the comments they helped a lot

MySQL - tell if column _all_ has same value

I'm trying to write a query like
if (select count(*) from Users where fkId=5000 and status='r') =
(select count(*) from Users where fkId=5000) then ..
in just one query.
What this means is, if all the rows that have fkId=5000 also have status=r, then do something.
There can be any number of rows with fkId=5000, and any fraction of those rows could have status=r, status=k, status=l, status=a etc. I'm interested in the case where ALL the rows that have fkId=5000 also have status=r (and not any other status).
The way I'm doing it now is
how many rows with id=5000 and status = 'r'?
how many rows with id=5000?
are those numbers equal? then ..
I'm trying to figure out how to rewrite this query using only 1 query, instead of 2. Keyword ALL didn't seem to be able to write such a query (<> ALL is equivalent to NOT IN). I tried a couple of GROUP BY formulations but could not get the correct result to appear.
The most efficient way to do this is:
if not exists (select 1
from users
where fkid = 5000 and (status <> 'r' or status is null)
)
This will stop the query at the first non-matching row.
I suggest you to check for any rows with status not equal to 'r'
SELECT count(*)>0 FROM Users WHERE fkId = 5000 AND status != 'r'
In the following case, if the number 1 is "true" (which it is) then you'll get Yes back, and if not you'll get No back:
SELECT IF(1, 'Yes', 'No') AS yesorno
(Go ahead -- try it!)
In your case however, the following would be more appropriate:
SELECT IF (
(SELECT COUNT(*) FROM Users WHERE fkId=5000 AND status IN('r') AND status NOT IN('1', 'a', 'k')) = (SELECT COUNT(*) FROM Users WHERE fkId=5000),
'They are equal.',
'They are not equal.'
)
AS are_they_equal
By adding AS, you can manipulate the name of the "column" that's returned to you.
Hope that helps... Also, see this page if you'd like more info.
:)
EASY!
Simply join back to the same table. Here is the complete code for testing:
CREATE TABLE Users(id int NOT NULL AUTO_INCREMENT, fkID int NOT NULL, status char(1), PRIMARY KEY (id));
INSERT Users (fkID, status) VALUES (5000, 'r');
INSERT Users (fkID, status) VALUES (5000, 'r');
INSERT Users (fkID, status) VALUES (5000, 'r');
-- The next query produces "0" to indicate no miss-matches
SELECT COUNT(*) FROM Users u1 LEFT JOIN Users u2 ON u1.id=u2.id AND u2.status='r' WHERE u1.fkID=5000 AND u2.id IS NULL;
-- now change one record to create a miss-match
UPDATE Users SET status='l' WHERE id=3 ;
-- The next query produces "1" to indicate 1 miss-match
SELECT COUNT(*) FROM Users u1 LEFT JOIN Users u2 ON u1.id=u2.id AND u2.status='r' WHERE u1.fkID=5000 AND u2.id IS NULL;
DROP TABLE Users;
So all you need to test for in the result is that it's 0 (zero) meaning everything has fkID=5000 also has status='r'
If you properly index your table then joining back to the same table is not an issue and certainly beats having to do a 2nd query.
Besides the NOT EXISTS version - which should be the most efficient as it does no counting at all and exits as soon as it finds a value that doesn't match the conditions, there is one more way, that will work if status is not nullable and will be efficient if there is an index on (fkId, status):
IF EXISTS
( SELECT 1
FROM Users
WHERE fkId = 5000
HAVING MIN(status) = 'r'
AND MAX(status) = 'r'
)
There is one difference though. The above will show false if there are no rows at all with fkId=5000, while the NOT EXISTS version will show true - which is probably what you want anyway.