Search SQL Question Between Related Two Tables - php

I am writing some kind of search engine for my web application and i have a problem. I have 2 tables first of is projects table:
PROJECTS TABLE
id int(11) NO PRI NULL auto_increment
employer_id int(11) NO MUL NULL
project_title varchar(100) NO MUL NULL
project_description text NO NULL
project_budget int(11) NO NULL
project_allowedtime int(11) NO NULL
project_deadline datetime NO NULL
total_bids int(11) NO NULL
average_bid int(11) NO NULL
created datetime NO MUL NULL
active tinyint(1) NO MUL NULL
PROJECTS_SKILLS TABLE
project_id int(11) NO MUL NULL
skill_id int(11) NO MUL NULL
For example: I want ask this query to database:
1-) Skills are 5 and 7.
2-) Order results by created
3-) project title contains "php" word.
4-) Returned rows should contain projects.* columuns.
5-) Projects should be distinct(i don't want same projects in return of query).
Please write sql query that ensure these conditions. Thank You.

SELECT projects.*
FROM projects
WHERE EXISTS (
SELECT *
FROM projects_skills
WHERE skill_id = 5
AND project_id = projects.project_id
)
AND EXISTS (
SELECT *
FROM projects_skills
WHERE skill_id = 7
AND project_id = projects.project_id
)
AND project_title LIKE '%php%'
ORDER BY created
or
SELECT projects.*
FROM projects
WHERE EXISTS (
SELECT *
FROM projects_skills
WHERE skill_id IN (5, 7)
AND project_id = projects.project_id
)
AND project_title LIKE '%php%'
ORDER BY created
Depending on what your intended result is.

It sounds like you're looking for an EXISTS query, which verifies that matching rows exist in a table, but without performing a JOIN.
SELECT *
FROM projects
WHERE EXISTS (SELECT 1 FROM projects_skills AS ps WHERE ps.project_id = projects.project_id AND ps.skill_id IN (5, 7))
AND project_title LIKE '%php%'
ORDER BY created;

Related

MySQL: "Patch" existing data on a table from values in another table

I have two tables, identical in structure. First one is populated with records obtained from another system that potentially needs corrections (could be one or many columns). Second table is corrections that I want to apply to the first table.
For example, I could have the following rows on table1:
order_number | name | email | tracking_no
101 null foo#bar.com 3456789
102 An Example ex#ample.com 1010101
...and the corrections I want to apply to these rows on table2:
order_number | name | email | tracking_no
101 Name Surname null null
102 null null 45778901
Essentially: Add missing name to order_number 101 and correct the wrong tracking_no for order_number 102.
The logic of what I am trying to do is: "Patch" values in table1 with the corrections contained for the same order_number in table2, giving precedence over to values in table2 and not overwriting existing values in table1 if the corresponding value in table2 is a null.
For the case where a value is null in table1 and we have a non-null correction in table2, COALESCE seems to be the right way to go but I can't figure out how to overwrite an already existing value with the corresponding "fix" from table2.
Is there a mechanism in MySQL/MariaDB that would allow me to do this as the alternative is a very messy "pull two records from two tables, compare values and build up the new correct record and insert it back into table1".
As pointed out in comments, here is a reproducible set of test data along with table structures:
USE so_demo;
DROP TABLE IF EXISTS so_demo.table1;
DROP TABLE IF EXISTS so_demo.table2;
CREATE TABLE so_demo.table1 (
order_number int(11) NOT NULL AUTO_INCREMENT,
name varchar(50) DEFAULT NULL,
email varchar(250) DEFAULT NULL,
tracking_no varchar(255) DEFAULT NULL,
PRIMARY KEY (order_number),
UNIQUE INDEX UK_table1_order_number (order_number)
)
ENGINE = INNODB,
CHARACTER SET utf8mb4,
COLLATE utf8mb4_general_ci;
CREATE TABLE so_demo.table2 (
order_number int(11) NOT NULL AUTO_INCREMENT,
name varchar(50) DEFAULT NULL,
email varchar(250) DEFAULT NULL,
tracking_no varchar(255) DEFAULT NULL,
PRIMARY KEY (order_number),
UNIQUE INDEX UK_table2_order_number (order_number)
)
ENGINE = INNODB,
CHARACTER SET utf8mb4,
COLLATE utf8mb4_general_ci;
INSERT INTO so_demo.table1 VALUES (101, NULL, "foo#bar.com", 3456789);
INSERT INTO so_demo.table1 VALUES (102, "An Example", "ex#ample.com", 1010101);
INSERT INTO so_demo.table2 VALUES (101, "Name Surname", NULL, NULL);
INSERT INTO so_demo.table2 VALUES (102, NULL, NULL, 45778901);
The term you are looking for is merge and in mysql an insert on duplicate key
drop table if exists t,t1;
create table t(order_number int primary key, name varchar(20) , email varchar(20), tracking_no int);
insert into t values
(101 , null , 'foo#bar.com' , 3456789),
(102 , 'An Example', 'ex#ample.com' , 1010101);
create table t1(order_number int, name varchar(20), email varchar(20), tracking_no int);
insert into t1 values
(101 , 'Name Surname', null , null),
(102 , null , null , '45778901');
insert into t
select * from t1
on duplicate key update
t.name = case when t1.name is not null then t1.name else t.name end,
t.email = case when t1.email is not null then t1.email else t.email end,
t.tracking_no = case when t1.tracking_no is not null then t1.tracking_no else t.tracking_no end
;
select * from t;
+--------------+--------------+--------------+-------------+
| order_number | name | email | tracking_no |
+--------------+--------------+--------------+-------------+
| 101 | Name Surname | foo#bar.com | 3456789 |
| 102 | An Example | ex#ample.com | 45778901 |
+--------------+--------------+--------------+-------------+
2 rows in set (0.001 sec)

PHP MySQLi Check if user voted if so other users can vote also

I have this working fine(I'm a relatively new coder) as long as there is 1 vote. How can I get other users to vote? code below:.
SELECT
b.id,
b.image_1_file,
b.your_name,
b.your_votes,
b.image_2_file,
b.battling_with_name,
b.battling_with_votes
FROM
battles b left outer join
votes v
on
b.id = v.battle_id
where
v.battle_id is null
order by
rand()
limit 1
and I tried:
SELECT
b.id,
b.image_1_file,
b.your_name,
b.your_votes,
b.image_2_file,
b.battling_with_name,
b.battling_with_votes
FROM
battles b
WHERE
b.id NOT IN (
SELECT
v.battle_id
FROM
votes v
WHERE
v.voters_id != '$myid'
)
order by
rand()
of course the latter will only look for b.id
other users have an id variable: $my_id
I don't want the member to see the image again after they have voted.
Thanks a lot for your help and have a blessed day!
My table structures are:
my images(to vote on) table:
id int(10) unsigned NO PRI auto_increment
image_1_file varchar(40) NO
image_2_file varchar(40) NO
your_name varchar(50) NO
your_votes int(10) NO 0
battlingwithname varchar(15) NO
battlingwithvotes int(10) NO 0
my votes(votes are stored) table:
id int(10) unsigned NO PRI auto_increment
battle_id int(10) unsigned NO
vote_type tinyint(1) unsigned NO
voters_id varchar(30)
just use not in operator, you have t ignore those id from projection who is already voted, so you have to pick up those id who voted and remove from projection by using not in note:another operator exist can also be used but i used not in my query
SELECT
b.id,
b.image_1_file,
b.your_name,
b.your_votes,
b.image_2_file,
b.battling_with_name,
b.battling_with_votes
FROM
battles b
where b.id not in( select v.battle_id from votes v)

exclude records that exist in another table

I got 2 tables like these:
emails:
emailID int(10) auto_increment, memberID int(10), emailData text, and so on
members:
memberID int(10) auto_increment, user_name char(40), password char(50), and so on
My query is this:
select
emails.emailID, emails.emailData,
members.memberID, members.user_name
from emails, members where
emails.memberID = members.memberID
Now I've added two more tables like these:
blocked:
id int(10) auto_increment, memberID int(10), blocked_memberID int(10)
markedAsRead:
id int(10) auto_increment, memberID int(10), emailID int(10)
I want to modify my original query so that it excludes memberID which are in blocked.blocked_memberID and also excludes emailID which are in markedAsRead.emailID
How can I do this?
You can use NOT EXISTS :
SELECT ....
FROM ....
WHERE ..... // Replace the dots with Your Query
AND NOT EXISTS(SELECT 1 FROM blocked
WHERE emails.memberID = blocked.memberID)
AND NOT EXISTS(SELECT 1 FROM markedAsRead
WHERE emails.emailID = markedAsRead.emailID)
You could also lookup for LEFT JOINS or NOT IN to exclude records that doesn't exists in a particular table.
EDIT: Usually EXISTS() and LEFTJOIN have similar performaces, sometime it can even perform better than a join.
LEFT JOIN sulotion:
SELECT ...
FROM ...
LEFT JOIN blocked
ON(WHERE emails.memberID = blocked.memberID)
LEFT JOIN markedAsRead
ON(emails.emailID = markedAsRead.emailID)
WHERE ...
AND blocked.memberID IS NULL
AND markedAsRead.emailID IS NULL

Single Table Messaging System in MySQL

I am currently working on a messaging system for one of my project. I am using single table to store messages and replies(i.e with parent_id).
Here is the table structure:
CREATE TABLE IF NOT EXISTS `messages` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(10) unsigned NULL,
`sender_id` int(10) unsigned NOT NULL,
`receiver_id` int(10) unsigned NOT NULL,
`who` enum('bride','member') NOT NULL,
`subject` varchar(200) NOT NULL,
`body` text NOT NULL,
`sent_date` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;
Where parent_id is the id of the message to which we replied. if parent_id=NULL then its a new message
Where who is the who sent that message- i.e bride or members. I have two separate tables for bride & member details.
Now I want a query to list messages in INBOX(just like GMAIL- bunch of conversations[messages+replies to that]).
Can you please help me to build the query?
This is what I was working on :
SELECT id
, parent_id
, sender_id
, receiver_id
, who
, subject
, body
, sent_date
FROM `messages`
WHERE sent_date IN ( SELECT MAX( sent_date ) FROM `messages` WHERE receiver_id = 1 GROUP BY sender_id )
AND who = 'bride'
AND receiver_id = 1
ORDER
BY id DESC
LIMIT 0, 8
This will give you all top-level messages (ie. not a reply) sent to a person identified with ID 1, as well as all direct replies to these messages (1 level deep, no recursion):
SELECT
messages.*,
replies.*
FROM messages
LEFT JOIN messages AS replies ON (replies.parent_id = messages.id)
WHERE messages.receiver_id = 1
ORDER BY id messages.sent_date, replies.sent_date
Now, from your sample code, it looks like you only want the latest message (and their replies), then:
SELECT
lastMessage.*,
replies.*
FROM (
SELECT * FROM messages ORDER BY sent_date
WHERE messages.receiver_id = 1
LIMIT 1
) AS lastMessage
LEFT JOIN messages AS replies ON (replies.parent_id = lastMessage.id)
ORDER BY id replies.sent_date
I do not understand the condition who = 'bride' though.

Auto Increment two columns

I'm trying to auto increment the art_id in the table below based on the art_userid, Is this possible without writing any extra php code? The gen_id has to remain and cannot be removed. I'm using Mysql and Php
CREATE TABLE `articles` (
`gen_id` INT(10) NULL AUTO_INCREMENT,
`art_id` TINYINT(3) NULL DEFAULT '0',
`art_userid` INT(10) NULL DEFAULT '0',
`art_title` VARCHAR(150) NULL DEFAULT NULL,
PRIMARY KEY (`gen_id`)
So in the end, if user 1 posted an article, his art_id would be 1. The next one he posts would have the id 2.
But if user 2 posted and article, his art_id would be 1 again. The next one he posts would have the id 2. Not the continuation of the 1st users art_id.
gen_id | art_id | art_userid | art_title
-----------------------------------------
1 1 1 Title A
2 2 1 Title B
3 1 2 Title A
4 2 2 Title B
5 3 1 Title A
Your strategy to increment art_id is different than auto-increment. so you cant use default one in query. But You can write TRIGGER, which will update art_id ON INSERT using art_userid.
in that case you should do a table that links user and article with each id.
because here there is no autoincrement to do, it's just a data management :)
regards
a more common approach is
CREATE TABLE `articles` (
`id` INT AUTO_INCREMENT, -- entry in table
`gen_id` INT(10) NULL ,
`art_id` TINYINT(3) NULL DEFAULT '0',
`art_userid` INT(10) NULL DEFAULT '0',
`art_title` VARCHAR(150) NULL DEFAULT NULL,
PRIMARY KEY(`id`)
)
use an id column in table so you specifie entries increment total articles of a user by a query
UPDATE total_articles SET total_articles=total_articles+1 WHERE userid=1
Well, I kinda solved it, but with one less column. The engine type needs to be MyIsam for this. Then do a create like this:
CREATE TABLE `articles` (
`art_id` INT(10) NOT NULL AUTO_INCREMENT,
`art_userid` INT(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`art_userid`, `art_id`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
Then when you insert art_userid, you'll get a unique value for art_id starting from 1 for each user.

Categories