SQL exclusive or on insert - mysql

if've got three tables in my MYSQL Database and want to connect two of this table with one table. The tables look like this
CONNECTTABLE
+----+-----------+---------+
| ID | search_id | room_id |
+----+-----------+---------+
SEARCHTABLE
+----+-----------+-----+
| ID | search_id | ... |
+----+-----------+-----+
SEARCHTABLE
+----+---------+-----+
| ID | room_id | ... |
+----+---------+-----+
Is it possible to ensure via MYSQL that in the CONNECTTABLE only search_id OR room_id is not null per datarow? If I can do so, how can I do so?
Valid rows:
+----+-----------+---------+
| ID | search_id | room_id |
+----+-----------+---------+
| 1 | 42 | NULL |
+----+-----------+---------+
| 2 | NULL | 1337 |
+----+-----------+---------+
Invalid row:
+----+-----------+---------+
| ID | search_id | room_id |
+----+-----------+---------+
| 3 | 42 | 17 |
+----+-----------+---------+
Best regards,
Gerrit

What you want is called a "CHECK constraint". Unfortunately, MySQL does not support them. Well, it will let you define them, but it won't actually check them. This article discusses using triggers to implement the same functionality.

hope this helps
select * from tableName where search_id is null && room_id is not null
union
select * from tableName where search_id is not null && room_id is null

First of all, it is not possible to add two tables with the same name in the database. But i presume that this are only dummy tablenames right? try this one:
SELECT a.ID, b.Search_ID, c.Room_ID
FROM ConnectTable a LEFT JOIN SearchTableA b
ON a.ID = b.ID
LEFT JOIN SearchTableB c
ON a.ID = c.ID
WHERE b.ID IS NULL OR
c.ID IS NULL

Related

Conditionally delete last row in mysql

How do I conditionally delete the last row in a mysql table?
me/my_machine#17:26:57>cat create_tables.sql
CREATE DATABASE IF NOT EXISTS test_db;
USE test_db;
CREATE TABLE IF NOT EXISTS err_hist_table (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
cl INT NOT NULL,
usr VARCHAR(16),
fault_code VARCHAR(10));
INSERT INTO err_hist_table (cl,usr,fault_code) VALUES (1,'pA','A'), (2,'pA','NULL'),(3,'pC','B'),(4,'pB','NULL');
The above SQL commands create a table that is like this:
MySQL [test_db]> SELECT * FROM err_hist_table;
+----+----+------+------------+
| id | cl | usr | fault_code |
+----+----+------+------------+
| 1 | 1 | pA | A |
| 2 | 2 | pA | NULL |
| 3 | 3 | pC | B |
| 4 | 4 | pB | NULL |
+----+----+------+------------+
4 rows in set (0.00 sec)
Now I want to DELETE the last row (biggest value of id) only when the value of fault_code is NULL. If it is not NULL, I want to skip the delete.
To my sql-newbie eyes, it seems like there should be a simple something like:
SELECT * IF err_history_table.id=max(err_history_table) AND fault_code = 'NULL';
I could not find my answer on the mysql docs page. Is there a simple solution for something like this?
You can do it with a subquery that returns the row of the maximum id where you check the value of fault_code:
DELETE FROM err_hist_table
WHERE id = (
SELECT id FROM (
SELECT * FROM err_hist_table
ORDER BY id DESC LIMIT 1
) t
WHERE fault_code IS NULL
);
See the demo.
Results:
| id | cl | usr | fault_code |
| --- | --- | --- | ---------- |
| 1 | 1 | pA | A |
| 2 | 2 | pA | |
| 3 | 3 | pC | B |
I'm not totally sure if this is what you want, but it should work. If you have a recent version of MySQL you should be able to use sub-queries, like this:
DELETE FROM err_hist_table WHERE id = (SELECT MAX(id) FROM err_hist_table) AND fault_code IS NULL
Untested on your specific table of course. I would even suggest performing a SELECT first to verify it does what you expect.
It's worth mentioning that you can acheive the desired result using a single JOIN, without needing a sub-sub-query and in a way which seems to me both concise and readable:
DELETE e1 FROM err_hist_table e1
JOIN (
SELECT MAX(id) AS id
FROM err_hist_table
) e2 USING (id)
WHERE e1.fault_code = 'NULL'
More on the topic of using joins in a DELETE statement here: https://dev.mysql.com/doc/refman/8.0/en/delete.html#idm45306662494864

MySQL NOT IN Select

I have a following table in my project
+----+--------+-----------+-----------+
| id | old_id | op_status | tr_status |
+----+--------+-----------+-----------+
| 1 | | issue | Approved |
| 2 | | issue | Approved |
| 3 | | issue | Approved |
| 4 | 1 | issue | Issued |
| 5 | 3 | issue | Issued |
+----+--------+-----------+-----------+
I want to select records WHERE tr_status='Approved' and NOT IN id in the old_row_id. In this example no need to select id(s) 1 and 3 that are in old_row_id as the following result.
+----+--------+-----------+-----------+
| id | old_id | op_status | tr_status |
+----+--------+-----------+-----------+
| 2 | | issue | Approved |
+----+--------+-----------+-----------+
I used the following query.
SELECT id, old_row_id, op_status, tr_status FROM table WHERE id NOT IN (old_row_id).
But outs the following result.
+----+--------+-----------+-----------+
| id | old_id | op_status | tr_status |
+----+--------+-----------+-----------+
| 1 | | issue | Approved |
| 2 | | issue | Approved |
| 3 | | issue | Approved |
+----+--------+-----------+-----------+
What may be wrong with me ? can anyone help me ?
I would phrase your query using exists logic:
SELECT t1.id, t1.old_id, t1.op_status, t1.tr_status
FROM yourTable t1
WHERE
t1.tr_status = 'Approved' AND
NOT EXISTS (SELECT 1 FROM yourTable t2 WHERE t2.old_id = t1.id);
Demo
Try doing something like this:
SELECT id, old_id, op_status, tr_status
FROM table
WHERE id NOT IN (SELECT DISTINCT old_id FROM table)
AND tr_status = 'Approved'
You will want to left join the table to itself on the old ID, then eliminate the records where there is a match.
For example:
SELECT A.id, A.old_row_id, A.op_status, A.tr_status
FROM table A
LEFT JOIN table B ON A.id = B.old_row_id
WHERE B.id IS NULL
AND A.tr_status = 'Approved';
In they way you've tried to solve it, you're matching the old_id with the value of the row itself. You must derivate the table to create a cartesian product:
SELECT id, old_id, op_status, tr_status
FROM table
WHERE id NOT IN (SELECT IFNULL(old_id, 0) FROM table)
AND tr_status = 'Approved'
Also IFNULL to also include those record in the subquery, otherwise can't be compared with null

Join 2 tables and create a new row showing if table 2 exists in table 1

I have this two tables
Table 1
+-----------+----------+
| support_id| Name |
+-----------+----------+
| 1 | Name 1 |
| 2 | Name 2 |
+-----------+----------+
Table 2
+-----------+----------+
| school_id | support_id|
+-----------+----------+
| 2314 | 1 |
+-----------+----------+
Desire output
+-----------+----------+------------+
| school_id |support_id| has |
+-----------+----------+------------+
| 2314 | 1 | Yes |
| 2314 | 2 | No |
+-----------+----------+------------+
How can I add the third row telling me if table 2 is in table 1?
Thanks in advance!
What do you mean a table1 "is" in table2?
The field support_id is the same as the support_id in table 2?
Or the field or the school_id is the same?
You need a field to be the same in both tables in order to make a connection (Foreign Key), make a join and connect both tables.
Considering support_id to be the foreigh key (the value shared between both tables) you can use this select:
SELECT school_id, IF(support_id is not null, "Yes", "No") as Has
FROM table1 LEFT JOIN table2
ON table1.support_id = table2.support_id;
I'd use a left join and then a case expression to format the results:
SELECT t2.*, CASE WHEN t1.support_id IS NOT NULL THEN 'Yes' ELSE 'No' END
FROM t2
LEFT JOIN t1 ON t2.support_id = t1.support_id

Using SELECT to get id, then get another column from another row

I have a table setup like this:
id (INT) | display_name (VARCHAR) | referral (INT)
referral is the id of the referral user. Is there a way that I can pull the referral ID, then use that to get the display_name of the referring member in one call? Or is it easier to do with two separate calls?
Essentially, all you'd need to do is JOIN your table on itself.
SELECT child.*, parent.display_name AS referral_name
FROM users AS child
JOIN users AS parent ON child.referral = parent.id
WHERE child.id = 2
This aliases the users table as child, then joins on the same table (aliased as parent).
+----+--------------+----------+---------------+
| id | display_name | referral | referral_name |
+----+--------------+----------+---------------+
| 2 | Jim | 1 | Tim |
+----+--------------+----------+---------------+
If the referral relationship may not exist, then you can use a LEFT JOIN instead:
SELECT child.*, parent.display_name AS referral_name
FROM users AS child
LEFT JOIN users AS parent ON child.referral = parent.id
+----+--------------+----------+---------------+
| id | display_name | referral | referral_name |
+----+--------------+----------+---------------+
| 1 | Tim | NULL | NULL |
| 2 | Sam | 1 | Tim |
| 3 | Kimberly | 1 | Tim |
+----+--------------+----------+---------------+
The following query will do what you want by joining the table with itself.
select t2.display_name from table_name t1 join table_name t2 on t1.referral=t2.id
where table_name is your table's name.

Dropping all duplicate rows in mySQL 5.7.9?

I want to drop all rows in a table of mySQL that have a duplicate using GROUP BY. My table has fields name date position email and looks like
+----------+---------------+----------+--------------------+
| M | 1976-10-03 | 1 | m#gmail |
| R | 1982-03-26 | 2 | r#gmail.com |
| C | 1987-09-03 | 3 | c#gmail.com |
| M | 1976-10-03 | 1 | m#gmail |
+----------+---------------+----------+--------------------+
I want to get
+----------+---------------+----------+--------------------+ |
| R | 1982-03-26 | 2 | r#gmail.com |
| C | 1987-09-03 | 3 | c#gmail.com |
+----------+---------------+----------+--------------------+
My attempt (from the answers to similar questions)
DELETE FROM ts1 WHERE * IN (SELECT * FROM ts1 GROUP BY * HAVING COUNT(*)>1);
Where are the errors? I understand I'm using too many * but I want to avoid naming all columns because they are too many in my actual table. Notice that I want to check for duplicates over the entire row.
You can't use GROUP BY * - you want to use GROUP BY name:
DELETE FROM ts1 WHERE name IN (SELECT name FROM ts1 GROUP BY name HAVING COUNT(*)>1);
Note that this would assume that users have unique names.
So you may actually want to check their emails instead:
DELETE FROM ts1 WHERE email IN (SELECT email FROM ts1 GROUP BY email HAVING COUNT(*)>1);