I'm having a really hard time figuring this one out. I am trying to make a conversation system and it would work like this:
A logged in user would have a link to "conversations". On that page a list of all conversation.titles would show up. When a conversation-name is clicked the conversation messages (mostly between 2 users, but could be more) will show up like this:
Conversation tiltle...
|------------------------------------------------------------|
|Send-button| Textfield for new message here |
|----------------|-------------------------------------------|
Sender: Hi....... (08/24/11 - 12PM)
receiver: Hi!..... (08/24/11 - 11PM
Sender: bla blah... (08/24/11 - 10PM)
etc..
I have no problem listing messages in the conversation itself, but rather getting the list of conversations a user participates in.
I get multiple results of the same instance.
I would like a query that produces a list of all conversations a logged in user has participated in either by sending a message, recieving a message or both.
I guess i would need a nested query, but i dont know how to do that. So i'm a bit stuck here, trying to inner-join all tables doesnt cut the cheese.
This is the database mysql design / ER-modell:
-- -----------------------------------------------------
-- Table `firm`.`conversation`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `firm`.`conversation` (
`conversation_id` INT NOT NULL AUTO_INCREMENT ,
`title` VARCHAR(45) NULL ,
`date` TIMESTAMP NULL ,
PRIMARY KEY (`subject_id`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `firm`.`message`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `firm`.`message` (
`message_id` INT NOT NULL AUTO_INCREMENT ,
`message` LONGTEXT NULL ,
`date` TIMESTAMP NOT NULL ,
`read_sender` BINARY NOT NULL ,
`read_receiver` BINARY NOT NULL ,
`deleted_receiver` BINARY NOT NULL ,
`deleted_sender` BINARY NOT NULL ,
`conversation_id` INT NOT NULL ,
PRIMARY KEY (`message_id`) ,
INDEX `fk_message_subject1` (`subject_id` ASC) ,
CONSTRAINT `fk_message_con1`
FOREIGN KEY (`conversation_id` )
REFERENCES `firm`.`conversation` (`conversation_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1
COLLATE = latin1_swedish_ci;
-- -----------------------------------------------------
-- Table `firm`.`outbox`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `firm`.`outbox` (
`outbox_id` INT NOT NULL AUTO_INCREMENT ,
`user_id` INT(10) NOT NULL ,
`conversation_id` INT(10) NOT NULL ,
`date` TIMESTAMP NOT NULL ,
PRIMARY KEY (`outbox_id`) ,
INDEX `fk_outbox_users1` (`user_id` ASC) ,
INDEX `fk_utbox_con1` (`conversation_id` ASC) ,
CONSTRAINT `fk_outbox_users1`
FOREIGN KEY (`user_id` )
REFERENCES `firm`.`users` (`user_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_outbox_con1`
FOREIGN KEY (`conversation_id` )
REFERENCES `firm`.`conversation` (`conversation_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
-- -----------------------------------------------------
-- Table `firm`.`inbox`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `firm`.`inbox` (
`inbox_id` INT NOT NULL ,
`user_id` INT(10) NOT NULL ,
`message_id` INT NOT NULL ,
`read` BINARY NOT NULL ,
`date` TIMESTAMP NOT NULL ,
PRIMARY KEY (`inbox_id`) ,
INDEX `fk_inbox_users1` (`user_id` ASC) ,
INDEX `fk_inbox_message` (`message_id` ASC) ,
CONSTRAINT `fk_inbox_users1`
FOREIGN KEY (`user_id` )
REFERENCES `firm`.`users` (`user_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_inbox_message1`
FOREIGN KEY (`message_id` )
REFERENCES `frim`.`message` (`message_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SELECT DISTINCT conversation.conversation_id
FROM conversation
INNER JOIN message ON message.conversation_id = conversation.conversation_id
INNER JOIN inbox ON inbox.message_id = message.message_id
INNER JOIN outbox ON inbox.message_id = message.message_id
WHERE outbox.user_id = #USER#
OR inbox.user_id = #USER#
This join should work. DISTINCT because a user is likely to have participated as a sender and a recipient.
Related
I do not know if it's possible at all, but I have two tables, userBasic and carPlateConfidence, in carPlateConfidence I would like to insert id of userBasic where emails are matched.
$query .= "INSERT IGNORE INTO userBasic (id_uM, userNameG, userEmailG) values ((SELECT id_uM FROM userMore WHERE userEmailG='$userEmailG'),'$userNameG', '$userEmailG');";
$query .= "INSERT IGNORE INTO carPlateConfidence (emailConfid, id_uB,plateNumber, confidencePlate, plateNumberUn) values ('$userEmailG', (SELECT id_uB FROM userBasic WHERE userEmailG='(SELECT max(emailConfid) FROM carPlateConfidence)'), '$plateNumber','$confidencePlate', '$plateNumberUn');";
So if I have:
userBasic:
id_uM = 555;
userNameG = BlaBla;
userEmailG = blabla#blabla.com
And in this table I would like
carPlateConfidence:
emailConfid = blabla#blabla.com;
id_uB = 555
plateNumber = 1111
confidencePlate = 70
plateNumberUn = 2222
AND if email do not matched:
emailConfid = blabla2#blabla.com;
id_uB = NULL
plateNumber = 1111
confidencePlate = 70
plateNumberUn = 222
P>S> Currently I have tried this, to select id from userBasic:
(SELECT id_uB FROM userBasic WHERE userEmailG='(SELECT max(emailConfid) FROM carPlateConfidence)')
id_uB in carPlateConfidence is set as foreign key;
Tables:
--
-- Table structure for table `carPlateConfidence`
--
DROP TABLE IF EXISTS `carPlateConfidence`;
CREATE TABLE IF NOT EXISTS `carPlateConfidence` (
`id_cof` int(11) NOT NULL AUTO_INCREMENT,
`id_uB` int(11) NOT NULL,
`emailConfid` varchar(50) NOT NULL,
`plateNumber` varchar(10) NOT NULL,
`confidencePlate` varchar(10) DEFAULT NULL,
`plateNumberUn` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id_cof`),
KEY `id_uB` (`id_uB`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
-- --------------------------------------------------------
--
-- Table structure for table `userBasic`
--
DROP TABLE IF EXISTS `userBasic`;
CREATE TABLE IF NOT EXISTS `userBasic` (
`id_uB` int(11) NOT NULL AUTO_INCREMENT,
`id_uM` int(11) NOT NULL,
`userNameG` varchar(50) NOT NULL,
`userEmailG` varchar(50) NOT NULL,
PRIMARY KEY (`id_uB`),
UNIQUE KEY `userEmailG` (`userEmailG`),
KEY `id_uM` (`id_uM`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=119 ;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `carPlateConfidence`
--
ALTER TABLE `carPlateConfidence`
ADD CONSTRAINT `carPlateConfidence_ibfk_1` FOREIGN KEY (`id_uB`) REFERENCES `userBasic` (`id_uB`);
--
-- Constraints for table `userBasic`
--
ALTER TABLE `userBasic`
ADD CONSTRAINT `userBasic_ibfk_1` FOREIGN KEY (`id_uM`) REFERENCES `userMore` (`id_uM`);
So you want an update, not an insert :
UPDATE carPlateConfidence t
SET t.id_uB = (SELECT distinct s.id_uM FROM userBasic s
WHERE s.userEmailG = t.emailConfid)
This will work only if there can be only 1 match, if there can be more then one match you should specify which one you want, if it doesn't matter, either use MAX() or limit :
UPDATE carPlateConfidence t
SET t.id_uB = (SELECT max(s.id_uM) FROM userBasic s
WHERE s.userEmailG = t.emailConfid)
I'm making a web app where users are posting their articles and other users can read them.
I wanna have a function in there where users can either save the articles that they like og remove those they don't wanna see anymore.
How should i set up my mysql tabels for that?
i'm thinking to have these tabels.
TABELS:
- articles
- users
- liked
- removed
I hope it makes sense?
You could probably build something similar to this:
Here is the SQL script to generate these tables:
-- tables
-- Table ArticleTypes
CREATE TABLE ArticleTypes (
ArticleTypeId int NOT NULL ,
ArticleTypeDesc varchar(255) NOT NULL ,
CONSTRAINT ArticleTypes_pk PRIMARY KEY (ArticleTypeId)
);
-- Table Articles
CREATE TABLE Articles (
ArticleId int NOT NULL ,
ArticleName varchar(255) NOT NULL ,
ArticleDescription varchar(255) NOT NULL ,
ArticleTypeId int NOT NULL ,
CONSTRAINT Articles_pk PRIMARY KEY (ArticleId)
);
-- Table BookmarkStatus
CREATE TABLE BookmarkStatus (
BookmarkStatusId int NOT NULL ,
BookmarkStatusDesc varchar(255) NOT NULL ,
CONSTRAINT BookmarkStatus_pk PRIMARY KEY (BookmarkStatusId)
);
-- Table Bookmarks
CREATE TABLE Bookmarks (
BookmarkId int NOT NULL ,
UserId int NOT NULL ,
ArticleId int NOT NULL ,
BookmarkStatusId int NOT NULL ,
CONSTRAINT Bookmarks_pk PRIMARY KEY (BookmarkId)
);
-- Table Users
CREATE TABLE Users (
UserId int NOT NULL ,
UserName varchar(255) NOT NULL ,
UserStatus int NOT NULL ,
CONSTRAINT Users_pk PRIMARY KEY (UserId)
);
-- foreign keys
-- Reference: Articles_ArticleTypes (table: Articles)
ALTER TABLE Articles
ADD CONSTRAINT Articles_ArticleTypes
FOREIGN KEY Articles_ArticleTypes (ArticleTypeId)
REFERENCES ArticleTypes (ArticleTypeId);
-- Reference: Bookmarks_Articles (table: Bookmarks)
ALTER TABLE Bookmarks
ADD CONSTRAINT Bookmarks_Articles
FOREIGN KEY Bookmarks_Articles (ArticleId)
REFERENCES Articles (ArticleId);
-- Reference: Bookmarks_BookmarkStatus (table: Bookmarks)
ALTER TABLE Bookmarks
ADD CONSTRAINT Bookmarks_BookmarkStatus
FOREIGN KEY Bookmarks_BookmarkStatus (BookmarkStatusId)
REFERENCES BookmarkStatus (BookmarkStatusId);
-- Reference: Bookmarks_Users (table: Bookmarks)
ALTER TABLE Bookmarks
ADD CONSTRAINT Bookmarks_Users
FOREIGN KEY Bookmarks_Users (UserId)
REFERENCES Users (UserId);
Basically, you can design your Bookmarks table to determine if the article is Active or Deleted based on the BookMarkStatusId (for e.g. 1 for Active, 2 for Deleted). Your bookmarks table will handle the relationship between users and articles tables.
Hope this helps!
i have a very annoying problem at this moment. i want a table with the following specification:
CREATE TABLE `test` (
`client` INT NOT NULL ,
`id` INT NOT NULL AUTO_INCREMENT ,
`test` INT NOT NULL ,
PRIMARY KEY ( `client` , `id` ) ,
INDEX ( `test` )
) ENGINE = INNODB;
you can see, that i have a primary key with 2 columns. now i want that the id auto_increment column only increments in order to the first column. for example:
## client/id ##
1/1
1/2
1/3
2/1
2/2
2/3
etc.
is this really impossible with innodb? i need innodb because of the transactional features.
You can derive it easily in SELECT statement
set #sno:=0;
set #client:='';
select #sno:=case when #client=client then #sno+1 else 1 end as sno,
#client:=client as client_id from table order by client;
I'm working on a web site where users can post articles with this table structure :
CREATE TABLE IF NOT EXISTS `articles` (
`id_articles` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_users` int(10) unsigned NOT NULL,
`articles` text NOT NULL,
PRIMARY KEY (`id_articles`),
UNIQUE KEY `id_articles` (`id_articles`),
KEY `id_users` (`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Each user can 'like' the articles.
Is that the right way below to create a 'like table' :
CREATE TABLE IF NOT EXISTS `articles_likes` (
`id_articles` int(10) unsigned NOT NULL,
`id_users` int(10) unsigned NOT NULL,
KEY `id_articles` (`id_articles`,`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
It is correct but you will want to add separte indexes on id_articles and id_users (also you might want to name the columns 'id_article' and 'id_user' for sanity).
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article` (`id_article`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
The reason you want separate indexes is because in mysql if you create an index on columns (A, B) that index will be used in queries having in the where clause column A, or columns A and B.
In your case for example if you made a query "SELECT * FROM article_likes WHERE id_user=X" this query would not use an index.
An ever better option would be to add a combined index and a separate index on the second column from the combined index. Like this:
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article_user` (`id_article`, `id_user`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
This way you would have optimal performance on queries like 'WHERE id_user=X', "WHERE id_article=X', "WHERE id_article=X AND id_user=Y"
This is a valid way Chris. You can use COUNT() to match the id_articles in the articles_likes table against the current article you are viewing in articles.
$articles_id = 23;
mysql_query("SELECT COUNT(*) FROM articles_likes
WHERE id_articles = ".$articles_id);
You can also just leave COUNT() (MySQL) out and instantly know which users are the "likers" of the articles and use count() (PHP) on the returned Array to duplicate the effect of COUNT() in MySQL.
i would have a total of 3 tables. an articles table, and the user id could be a column in that for users who submit articles , but you need a separate user table since not all users will submit articles (i am assuming), and then a 3rd table for likes, that takes the primary key from users and the primary key from articles and uses them as foreign keys. so each time an article is liked, an entry is made in the 3rd table
I have a database where I store keywords grouped into projects and data related to each keyword, then I display datagrids foreach project with one row per keyword and several columns all retrieved from the same table "data". I have 4 tables, keywords, projects, group_keywords and data. "keywords" only stores the keyword, "projects" the project name, "group_keywords" the keywords ids for the keywords assigned to that project, and "data" is where all the data foreach keyword goes, identified by a foreign key for the keywords.id, and a name column to identify the data name.
Now to retrieve the keywords + all the data for a project I use this query:
SELECT * FROM `group_keywords`
INNER JOIN keywords on keywords.id = keyword_id
INNER JOIN data ON data.id = keywords.id
WHERE `group_id` = (SELECT `id` FROM `projects` WHERE `name` = 'ProjectName'
This gives me something like
id group_id keyword_id id keyword id name value
12 5 52 52 absorption food 52 data_name_x1 6
12 5 52 52 absorption food 52 data_name_x2 8
12 5 52 52 absorption food 52 data_name_x3 26
12 5 52 52 absorption food 52 data_name_x4 2
...
But what I want is to get:
id group_id keyword_id id keyword id data_name_x1 data_name_x2 data_name_x3 data_name_x4
12 5 52 52 absorption food 52 6 8 26 2
...
So I can sort and use pagination for the datagrids easly, otherwise I have no idea how to do it, because when using big data sets I can't just dump everything into an array, too much data.
This is the schema:
-- --------------------------------------------------------
-- Table structure for table `keywords`
CREATE TABLE IF NOT EXISTS `keywords` (
`id` int(10) unsigned NOT NULL auto_increment,
`keyword` varchar(255) NOT NULL,
UNIQUE KEY `id` (`id`),
UNIQUE KEY `keyword` (`keyword`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=115386 ;
-- --------------------------------------------------------
-- Table structure for table `data`
CREATE TABLE IF NOT EXISTS `data` (
`id` int(10) unsigned NOT NULL,
`name` varchar(100) NOT NULL,
`value` varchar(15) NOT NULL,
UNIQUE KEY `id` (`id`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- --------------------------------------------------------
-- Table structure for table `projects`
--
CREATE TABLE IF NOT EXISTS `projects` (
`id` int(10) NOT NULL auto_increment,
`name` varchar(100) NOT NULL,
`parent` varchar(100) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=21 ;
-- --------------------------------------------------------
-- Table structure for table `group_keywords`
CREATE TABLE IF NOT EXISTS `group_keywords` (
`id` int(10) NOT NULL auto_increment,
`group_id` int(10) NOT NULL,
`keyword_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `group_id` (`group_id`,`keyword_id`),
KEY `keyword_id` (`keyword_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=119503 ;
-- --------------------------------------------------------
-- Constraints for table `data`
--
ALTER TABLE `data`
ADD CONSTRAINT `data_ibfk_1` FOREIGN KEY (`id`) REFERENCES `keywords` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- --------------------------------------------------------
-- Constraints for table `group_keywords`
--
ALTER TABLE `group_keywords`
ADD CONSTRAINT `group_keywords_ibfk_1` FOREIGN KEY (`keyword_id`) REFERENCES `keywords` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
This operation is traditionally called "unpivot" and a few RDBMSs support it, but MySQL doesn't appear to be one of them. You have two options, do it in SQL or do it in PHP. In MySQL it looks something like this with self-joins (I don't know which field qualifies as an ID field for you, so forgive me creating my own example). From a performance perspective, make sure you index both the ID and Column Name, otherwise these joins will crawl.
shapes
ID Name Value
1 Color Red
1 Shape Circle
... for more "columns"
2 Color Green
2 Shape Square
... for more "columns"
SELECT
A.ID,
B.Value as Color,
C.Value as Shape
... for more "columns"
FROM shapes A
LEFT JOIN shapes B ON B.ID = A.ID AND B.Name = 'Color'
LEFT JOIN shapes C ON C.ID = A.ID AND C.Name = 'Shape'
... for more "columns"
Which should net us (unless my head-SQL-parser is misrunning tonight):
ID Color Shape
1 Red Circle
2 Green Square
For the PHP version, you don't necessarily have to load up an array, you can stream it. Sort by the PK and walk down it setting the properties. In pseudocode:
Set X to undefined
Get a Record
Check the ID property, if it's different than X, create a new object, set X to the new ID, and yield the previous object
Set the property of the object based on the "Name" column of our result
Hope this helps!