How can I declare a constraint such that two columns may not have the same value in any row.
E.g. Given
create table `presents` (
`from` varchar(255) NOT NULL,
`to` varchar(255) NOT NULL
)
I want to make sure that nobody ever gives a present to themselves.
'alice', 'bob' # OK
'bob', 'charlie' # OK
'bob', 'alice' # OK
'bob', 'alice' # OK again
'bob', 'bob' # Fails
create table `presents` (
`from` varchar(255) NOT NULL,
`to` varchar(255) NOT NULL,
CHECK(from<>to)
)
Here's one idea:
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table (id SERIAL PRIMARY KEY, `from` INT NOT NULL, `to` INT NOT NULL);
INSERT INTO my_table (`from`,`to`) SELECT 1,2 FROM (SELECT 1) x WHERE 1 <> 2;
INSERT INTO my_table (`from`,`to`) SELECT 1,1 FROM (SELECT 1) x WHERE 1 <> 1;
SELECT * FROM my_table;
+----+------+----+
| id | from | to |
+----+------+----+
| 1 | 1 | 2 |
+----+------+----+
I have mysql table
CREATE TABLE `range` (
`id` int(11) NOT NULL,
`object_id` int NOT NULL,
`datetime_from` datetime NOT NULL,
`datetime_to` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Please help to provide on mysql level constraint implementation: no time interval intersection for same object_id.
A trigger is fine, but by way of demonstrating that no trigger is required, consider the following...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table (
id SERIAL,
dt_from DATE NOT NULL,
dt_to DATE NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO my_table (dt_from,dt_to)
VALUES
('2018-05-31','2018-06-03');
-- Attempt 1: conflicting dates
SET #dt_from = '2018-05-28';
SET #dt_to = '2018-06-01';
INSERT INTO my_table (dt_from,dt_to)
SELECT #dt_from
, #dt_to
FROM (SELECT 1) x
LEFT
JOIN my_table y
ON y.dt_from < #dt_to
AND y.dt_to > #dt_from
WHERE y.id IS NULL;
-- Attempt 2: Non-conflicting dates
SET #dt_from = '2018-06-04';
SET #dt_to = '2018-06-06';
INSERT INTO my_table (dt_from,dt_to)
SELECT #dt_from
, #dt_to
FROM (SELECT 1) x
LEFT
JOIN my_table y
ON y.dt_from < #dt_to
AND y.dt_to > #dt_from
WHERE y.id IS NULL;
SELECT * FROM my_table;
+----+------------+------------+
| id | dt_from | dt_to |
+----+------------+------------+
| 1 | 2018-05-31 | 2018-06-03 |
| 2 | 2018-06-04 | 2018-06-06 |
+----+------------+------------+
See. Conflicting dates are ignored.
I am returning a array of user created statuses in a feed. I have realized that looping through the mysql results in php post mysql to add on additional key/values ridiculously slows down our api response times so im trying to eliminate any foreach looping in php on this array of statuses.
here is my table setup:
USERS TABLE
UID / FIRST_NAME/ LAST_NAME/ECT
UPDATES TABLE
msg_id/message/ UID_FK
LIKED TABLE
LIKED_ID/ MSG_ID_FK/ LIKED_BY_UID
Is there a way that in mysql i can include a "isLiked" bool if the user making the api request has liked the update on each row returned in my query?
Here is my actual query im working with, it has a bit more data than i described in it but the goal is the same....find a way to add a 'isLiked' column to each row:
SELECT b.type,b.owner,b.update_img,b.ALBUM_ID,b.last_comment,a.uid, a.first_name, a.last_name, a.gender, a.thumb_img, b.msg_id, b.message, b.created,b.POST_PRIVACY
FROM users AS a, updates AS b, LIKED as c WHERE b.uid_fk = a.uid AND b.type<>'FRIEND_RELATIONSHIP'AND b.created<$time AND b.type<>'FAMILIAR_RELATIONSHIP' AND a.college='$college' AND b.POST_PRIVACY<>'4' AND b.POST_PRIVACY<>'5' AND b.created>=$tstamp ORDER BY b.created DESC
LIMIT 100
EDIT:
Here is a version of the query where I attempt to do what im aiming for ,but the problem is this ONLY returns the rows that I have liked:
SELECT b.type, b.owner, b.update_img, b.ALBUM_ID, b.last_comment, a.uid, a.first_name, a.last_name, a.gender, a.thumb_img, b.msg_id, b.message, b.created, b.POST_PRIVACY,c.LIKED
FROM users AS a, updates AS b, LIKES AS c
WHERE b.uid_fk = a.uid
AND b.POST_PRIVACY <> '4'
AND b.POST_PRIVACY <> '5'
AND c.LIKED_UID = '1'
AND b.msg_id = c.MSG_ID_FK
ORDER BY b.created DESC
LIMIT 100
If you are getting only the line with liked but want all the lines, try this:
SELECT b.type, b.owner, b.update_img, b.ALBUM_ID, b.last_comment, a.uid, a.first_name, a.last_name, a.gender, a.thumb_img, b.msg_id, b.message, b.created, b.POST_PRIVACY,c.LIKED
FROM users AS a, updates AS b, BUMPS AS c
WHERE b.uid_fk = a.uid
AND b.POST_PRIVACY <> '4'
AND b.POST_PRIVACY <> '5'
AND ((c.LIKED_UID = '1'
AND b.msg_id = c.MSG_ID_FK)
OR c.MSG_ID_FK IS NULL
)
ORDER BY b.created DESC
LIMIT 100
Added null test so that it is equivalent to a LEFT JOIN.
The column c.LIKED will be 1 when there is a liked on that message id and null when it doesn't.
-- EDIT --
As the above didn't work (may be wrong, I didn't test it), try this form of writing it (I like this way):
SELECT b.type, b.owner, b.update_img, b.ALBUM_ID, b.last_comment, a.uid, a.first_name, a.last_name, a.gender, a.thumb_img, b.msg_id, b.message, b.created, b.POST_PRIVACY,c.LIKED
FROM
users AS a
INNER JOIN updates AS b ON b.uid_fk = a.uid
LEFT JOIN BUMPS AS c ON b.msg_id = c.MSG_ID_FK
WHERE b.POST_PRIVACY <> '4'
AND b.POST_PRIVACY <> '5'
ORDER BY b.created DESC
LIMIT 100
Note that it will only select lines that are related on users and updates, and values from table BUMPS will be selected as NULL if no related line exists. This is what I recommend.
(deleted informations that could cause error and lead to confusion)
-- EDIT 2 added a test-case with simplified data and query --
I didn't see the entire problem before, then I did a test-case.
I created test tables and data:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `test_multi_sets`()
DETERMINISTIC
begin
select user() as first_col;
select user() as first_col, now() as second_col;
select user() as first_col, now() as second_col, now() as third_col;
end$$
DELIMITER ;
CREATE TABLE IF NOT EXISTS `BUMPS` (
`id` int(11) NOT NULL,
`MSG_ID_FK` int(11) NOT NULL,
`LIKED_UID` int(11) NOT NULL,
`LIKED` tinyint(4) NOT NULL DEFAULT '0'
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
INSERT INTO `BUMPS` (`id`, `MSG_ID_FK`, `LIKED_UID`, `LIKED`) VALUES
(1, 1, 1, 1),
(2, 3, 2, 0),
(3, 1, 2, 0);
CREATE TABLE IF NOT EXISTS `updates` (
`msg_id` int(11) NOT NULL,
`uid_fk` int(11) NOT NULL,
`text` varchar(20) NOT NULL,
`POST_PRIVACY` tinyint(4) NOT NULL DEFAULT '0'
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
INSERT INTO `updates` (`msg_id`, `uid_fk`, `text`, `POST_PRIVACY`) VALUES
(1, 1, 't11', 3),
(2, 1, 't12', 3),
(3, 2, 't21', 3),
(4, 2, 't22', 3);
CREATE TABLE IF NOT EXISTS `users` (
`uid` int(11) NOT NULL,
`name` varchar(20) NOT NULL,
`pass` varchar(20) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
INSERT INTO `users` (`uid`, `name`, `pass`) VALUES
(1, 'u1', 'p1'),
(2, 'u2', 'p2');
ALTER TABLE `BUMPS`
ADD PRIMARY KEY (`id`), ADD KEY `MSG_ID_FK` (`MSG_ID_FK`), ADD KEY `LIKED_UID` (`LIKED_UID`);
ALTER TABLE `updates`
ADD PRIMARY KEY (`msg_id`), ADD KEY `uid_fk` (`uid_fk`);
ALTER TABLE `users`
ADD PRIMARY KEY (`uid`);
ALTER TABLE `BUMPS`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=4;
ALTER TABLE `updates`
MODIFY `msg_id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=5;
ALTER TABLE `users`
MODIFY `uid` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=3;
ALTER TABLE `BUMPS`
ADD CONSTRAINT `bumps_ibfk_1` FOREIGN KEY (`LIKED_UID`) REFERENCES `users` (`uid`),
ADD CONSTRAINT `bumps_ibfk_2` FOREIGN KEY (`MSG_ID_FK`) REFERENCES `updates` (`msg_id`);
ALTER TABLE `updates`
ADD CONSTRAINT `updates_ibfk_1` FOREIGN KEY (`uid_fk`) REFERENCES `users` (`uid`);
and run this select:
SELECT a.uid, a.name, b.msg_id, b.text, b.POST_PRIVACY, c.LIKED
FROM users AS a
INNER JOIN updates AS b ON b.uid_fk = a.uid
LEFT JOIN BUMPS AS c ON (c.LIKED_UID = 1 AND b.msg_id = c.MSG_ID_FK)
WHERE NOT (b.POST_PRIVACY IN(4, 5)) LIMIT 100
with these results:
| uid | name | msg_id | text | POST_PRIVACY | LIKED
| 1 | u1 | 1 | t11 | 3 | 1
| 1 | u1 | 2 | t12 | 3 | NULL
| 2 | u2 | 3 | t21 | 3 | NULL
| 2 | u2 | 4 | t22 | 3 | NULL
Even that user 2 liked updates, it won't show on user1 query.
I hope this helps you to solve your problem. I believe that I can't go any further than this, but anyway, send a message if needed.
Caution if using this on your production server, as first scrip on the EDIT 2 will create tables.
In my db I've a table (t1) with this structure
CREATE TABLE IF NOT EXISTS 't1' (
'id_ric' int(11) NOT NULL AUTO_INCREMENT,
'id_tipoins' decimal(1,0) NOT NULL,
'datains' timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ('id_ric')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I create a view to count all record grouped by id_user in this way
CREATE VIEW view_users_app
AS
SELECT id_user, MAX(datains) last_datains, COUNT(*) totalCount
FROM t1
GROUP BY id_user
Now I'd like also count where id_tipoins = 1 and id_tipoins = 2 (grouped by id_user).
It's possible to do? How could I do this? Thanks
CREATE VIEW view_users_app
AS
SELECT id_user,
MAX(datains) last_datains,
COUNT(*) totalCount,
sum(id_tipoins = 1) as p1,
sum(id_tipoins = 2) as p2
FROM t1
GROUP BY id_user
How to fix this mysql query
SELECT no, name,
(SELECT chapter, max FROM table2 WHERE name = user.name AND max = 10)
as sub_array1,
(SELECT chapter, max FROM table2 WHERE name = user.name AND max = 20)
as sub_array2
FROM user ORDER by exp DESC
example expected out result:
the current query returns me Operand should contain 1 column(s)
basically i want to create something like this:
------------------------------------------------------------------------------
no | name | sub_array1
------------------------------------------------------------------------------
1 |myname | sub_array1[0][chapter]=chapter_1, sub_array1[0][max]=100
| | sub_array1[1][chapter]=chapter_2, sub_array1[1][max]=70
| | ...
------------------------------------------------------------------------------
2 |myname_2 | sub_array1[0][chapter]=chapter_1, sub_array1[0][max]=100
| | sub_array1[1][chapter]=chapter_2, sub_array1[1][max]=50
| | sub_array1[2][chapter]=chapter_3, sub_array1[2][max]=60
Actual query
SELECT
no, name, maxcombo, exp, level, location,
(
(SELECT chapter, MAX(score) as max, name
FROM chapter_test_progress
WHERE name = user.name AND type = 'vocabulary' GROUP BY chapter
)
) as user_chapter_test_statuses,
(
(SELECT chapter, MAX(score) as max, name
FROM chapter_test_progress
WHERE name = user.name AND type = 'kanji' GROUP BY chapter
)
) as user_chapter_test_status_kanjis
FROM
user
ORDER by
exp DESC
LIMIT $offset, $rowPerPage
Thank You,
I don't know if I correctly understand the structure of your database, but this should do it:
SELECT U.no, U.name, S.chapter, S.max
FROM user U,
(SELECT CP.chapter, MAX(CP.score) max, CP.name FROM chapter_test_progress CP GROUP BY name, chapter) S
WHERE U.name = S.name
GROUP BY U.name, S.chapter;
The test data I've used:
CREATE TABLE `chapter_test_progress` (
`chapter` varchar(255) DEFAULT NULL,
`score` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
insert into `chapter_test_progress`(`chapter`,`score`,`name`) values ('ch_1',10,'alice'),('ch_1',20,'alice'),('ch_2',10,'bob'),('ch_2',50,'bob'),('ch_1',100,'alice'),('ch_2',100,'alice'),('ch_1',200,'bob'),('ch_2',200,'bob');
CREATE TABLE `user` (
`no` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`no`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
insert into `user`(`no`,`name`) values (1,'alice'),(2,'bob');
You should normalize your database.