Joining two tables having two same columns - php

I am making a school project with mysql database.
Having this table ready, I need to create a query that will join ReciverID and SenderID with accounts.Email column. I have tried many solutions, but all my atempts resulted into duplicates or errors. The result should look like this.
I have table "accounts"
CREATE TABLE IF NOT EXISTS `accounts` (
`AccountID` INT(11) NOT NULL AUTO_INCREMENT,
`Email` VARCHAR(128) NOT NULL,
`Password` VARCHAR(128) NOT NULL,
`Balance` DOUBLE(10, 5) NOT NULL DEFAULT 10,
`VerifyCode` INT(6) NOT NULL,
PRIMARY KEY (`AccountID`),
UNIQUE INDEX `Email_UNIQUE` (`Email`),
UNIQUE INDEX `VerifyCode_UNIQUE` (`VerifyCode`)
)
And table "transactions"
CREATE TABLE IF NOT EXISTS `mydb`.`transactions` (
`TransactionID` INT(11) NOT NULL AUTO_INCREMENT,
`SenderID` INT(11) NOT NULL,
`ReciverID` INT(11) NOT NULL,
`Date` INT(32) NOT NULL,
`Note` VARCHAR(256) NULL DEFAULT NULL,
`Amount` DOUBLE(10, 5) NOT NULL,
PRIMARY KEY (`TransactionID`),
INDEX `Sender_idx` (`SenderID`),
INDEX `reciver_fk_idx` (`ReciverID`),
CONSTRAINT `reciver_fk` FOREIGN KEY (`ReciverID`) REFERENCES `accounts` (`AccountID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `sender_fk` FOREIGN KEY (`SenderID`) REFERENCES `accounts` (`AccountID`) ON DELETE NO ACTION ON UPDATE NO ACTION
)
Thanks for any reply!

You can try working with alias.
Something like
Select T.TransactionID, S.email, R.email, T.date, T.note, T.Amount
From Transactions T, Accounts S, Accounts R
Where T.SenderID = S.AccountID AND T.ReceiverID = R.AccountID AND
--The rest of your conditions
PS: I wouldn't recommend naming a column date... It's a key word usually resulting in errors
EDIT
Base on #HoneyBadger comment the comma joining style is out dated... So here's another way to do it
Select T.TransactionID, S.email, R.email, T.date, T.note, T.Amount
From Transactions T
Join Accounts S On T.SenderID = S.AccountID
Join Accounts R On T.ReceiverID = R.AccountID
--add your conditions

Related

MySQL query with large data performance

I'm a bit new to MySQL and I would like to know if I'm going right with these tables and query:
tb_anuncio
CREATE TABLE `tb_anuncio` (
`anuncio_id` int(11) NOT NULL auto_increment,
`anuncio_titulo` varchar(120) NOT NULL,
`anuncio_valor` decimal(10,2) NOT NULL,
`anuncio_valorTipo` int(11) default NULL,
`anuncio_telefone` varchar(20) NOT NULL,
`anuncio_descricao` text,
`anuncio_criado` timestamp NOT NULL default CURRENT_TIMESTAMP,
`bairro_id` int(11) NOT NULL,
`anuncio_status` int(11) default '0',
PRIMARY KEY (`anuncio_id`),
KEY `ta001_ix` (`bairro_id`)
) ENGINE=InnoDB DEFAULT charset utf8;
ALTER TABLE `tb_anuncio`
ADD CONSTRAINT `ta001_ix` FOREIGN KEY (`bairro_id`) REFERENCES `tb_bairro` (`bairro_id`) ON DELETE CASCADE ON UPDATE CASCADE;
tb_estado
CREATE TABLE `tb_estado` (
`estado_id` int(11) NOT NULL auto_increment,
`estado_nome` varchar(2) NOT NULL,
`estado_criado` timestamp NOT NULL default CURRENT_TIMESTAMP,
`estado_url` varchar(2) NOT NULL,
PRIMARY KEY (`estado_id`),
UNIQUE KEY `estado_url` (`estado_url`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
tb_cidade
CREATE TABLE `tb_cidade` (
`cidade_id` int(11) NOT NULL auto_increment,
`cidade_nome` varchar(100) NOT NULL,
`cidade_criado` timestamp NOT NULL default CURRENT_TIMESTAMP,
`estado_id` int(11) NOT NULL,
`cidade_url` varchar(150) NOT NULL,
PRIMARY KEY (`cidade_id`),
UNIQUE KEY `cidade_url` (`cidade_url`),
KEY `tc001_ix` (`estado_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `tb_cidade`
ADD CONSTRAINT `tc001_ix` FOREIGN KEY (`estado_id`) REFERENCES `tb_estado` (`estado_id`) ON DELETE CASCADE ON UPDATE CASCADE;
tb_bairro
CREATE TABLE `tb_bairro` (
`bairro_id` int(11) NOT NULL auto_increment,
`bairro_nome` varchar(100) NOT NULL,
`bairro_criado` timestamp NOT NULL default CURRENT_TIMESTAMP,
`cidade_id` int(11) NOT NULL,
`bairro_url` varchar(150) NOT NULL,
PRIMARY KEY (`bairro_id`),
UNIQUE KEY `bairro_url` (`bairro_url`),
KEY `tb001_ix` (`cidade_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `tb_bairro`
ADD CONSTRAINT `tb001_ix` FOREIGN KEY (`cidade_id`) REFERENCES `tb_cidade` (`cidade_id`) ON DELETE CASCADE ON UPDATE CASCADE;
Well I'm doing a query to show ads of a city/state, my query looks like:
Query
select a.anuncio_id,a.anuncio_titulo,a.anuncio_valor,a.anuncio_valorTipo,a.anuncio_descricao
from tb_anuncio a inner join(
tb_bairro b inner join(
tb_cidade c inner join
tb_estado d on d.estado_id=c.estado_id) on c.cidade_id=b.cidade_id) on b.bairro_id=a.bairro_id
where a.anuncio_status=1 and d.estado_id=:estado_id and c.cidade_id=:cidade_id and b.bairro_id=:bairro_id
group by a.anuncio_id
order by a.anuncio_id desc
limit :limit
I would like to know if I'm going right and it will work well when these tables get about 5k-10k of records.
I'm using PHP PDO MySQL.
Thanks.
Although it doesn't affect performance, the typical way to write a query would not have parentheses in the FROM clause. Also, I doubt the group by is necessary:
select a.*
from tb_anuncio a inner join
tb_bairro b
on b.bairro_id = a.bairro_id inner join
tb_cidade c
on c.cidade_id = b.cidade_id inner join
tb_estado e
on e.estado_id = c.estado_id
where a.anuncio_status = 1 and e.estado_id = :estado_id and
c.cidade_id = :cidade_id and b.bairro_id = :bairro_id
order by a.anuncio_id desc
limit :limit;
You can simplify this, because you do not need all the joins -- the join keys are in referencing tables:
select a.*
from tb_anuncio a inner join
tb_bairro b
on b.bairro_id = a.bairro_id inner join
tb_cidade c
on c.cidade_id = b.cidade_id
where a.anuncio_status = 1 and c.estado_id = :estado_id and
c.cidade_id = :cidade_id and b.bairro_id = :bairro_id
order by a.anuncio_id desc
limit :limit;
I don't know Portuguese, but seems like one estado contains many cidades, which contains many bairros. If this is correct, then the schema is wrong. Fixing the schema will lead to improving the performance.
There should be one bairro in the query, not three such items in the WHERE.
Furthermore, it is usually more practical for tb_bairro to include information about the cidade and estado, not tb_anuncio.
Once you have done those things, the GROUP BY can probably be eliminated, thereby adding more performance.
And add
INDEX(anuncio_status, bairro_id, anuncio_id)

improve MySQL query performance from slow query log

I turned on slow query monitor in MySQL config.
Below is the query and time:
Time: 160330 20:54:11
User#Host: user[user] # [xx.xx.xxx.xxx]
Query_time: 8.794170 Lock_time: 0.000141 Rows_sent: 3942 Rows_examined: 4742825
SET timestamp=1459371251;
SELECT (SELECT (CASE WHEN ce_type = 'IN' then SUM(payment_amount)
END) as debit
FROM customer_payment_options cpo
WHERE wallet_id=cw.id
AND (cpo.real_account_type='HQ')
AND cpo.source_country_id='40'
GROUP BY cpo.wallet_id)
as debit,
(SELECT SUM(payment_amount)
as credit
FROM customer_payment_options cpo
WHERE wallet_id=cw.id
AND (cpo.real_account_type='HQ')
AND cpo.tran_id IS NOT NULL
AND cpo.source_country_id='40'
GROUP BY cpo.wallet_id)
as credit
FROM customer_wallet cw
WHERE cw.company_id='1'
AND cw.currency='40'
AND cw.is_approved = '1'
AND DATE(cw.date_added) < '2016-03-30';
Indexes on customer_payment_options:
company_id
tran_id
ce_id
wallet_id
What should I do to improve it's performance?
EXPLAIN:
http://i.stack.imgur.com/iH8rt.png
SCHEMA
CREATE TABLE `customer_payment_options` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`company_id` int(11) NOT NULL,
`local_branch_id` int(11) NOT NULL,
`tran_id` bigint(11) DEFAULT NULL,
`ce_id` int(11) DEFAULT NULL,
`wallet_id` int(11) DEFAULT NULL,
`reward_credit_id` int(11) DEFAULT NULL,
`ce_invoice_id` varchar(32) DEFAULT NULL,
`ce_type` enum('IN','OUT') DEFAULT NULL,
`payment_type` enum('CASH','DEBIT','CREDIT','CHEQUE','DRAFT','BANK_DEPOSIT','EWIRE','WALLET','LOAN','REWARD_CREDIT') NOT NULL,
`payment_amount` varchar(20) NOT NULL,
`payment_type_number` varchar(100) DEFAULT NULL,
`source_country_id` int(11) NOT NULL,
`real_account_id` int(11) DEFAULT NULL,
`real_account_type` enum('LOCAL','HQ') DEFAULT NULL,
`date_added` datetime NOT NULL,
`event_type` enum('MONEY_TRANSFER','CURRENCY_EXCHANGE','WALLET') DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `company_id` (`company_id`),
KEY `real_account_type` (`real_account_type`),
KEY `tran_id` (`tran_id`),
KEY `ce_id` (`ce_id`),
KEY `wallet_id` (`wallet_id`),
CONSTRAINT `customer_payment_options_ibfk_4` FOREIGN KEY (`wallet_id`) REFERENCES `customer_wallet` (`id`),
CONSTRAINT `customer_payment_options_ibfk_1` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`),
CONSTRAINT `customer_payment_options_ibfk_2` FOREIGN KEY (`tran_id`) REFERENCES `transaction` (`id`),
CONSTRAINT `customer_payment_options_ibfk_3` FOREIGN KEY (`ce_id`) REFERENCES `currency_exchange` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=412 DEFAULT CHARSET=utf8
CREATE TABLE `customer_wallet` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`wallet_unique_id` varchar(100) DEFAULT NULL,
`company_id` int(11) NOT NULL,
`branch_admin_id` int(11) DEFAULT NULL,
`emp_id` int(11) DEFAULT NULL,
`emp_type` enum('SUPER_ADMIN','ADMIN','AGENT_ADMIN','AGENT','OVER_AGENT_ADMIN','OVER_AGENT') DEFAULT NULL,
`cus_id` bigint(11) NOT NULL,
`tran_id` bigint(11) DEFAULT NULL,
`beehive_id` int(11) DEFAULT NULL,
`type` enum('DEPOSIT','WITHDRAW','TRANSACTION') NOT NULL,
`sub_type` enum('MONEY_TRANSFER','BEEHIVE_DEPOSIT') DEFAULT NULL,
`credit_in` varchar(20) DEFAULT NULL,
`credit_out` varchar(20) DEFAULT NULL,
`currency` varchar(20) NOT NULL,
`date_added` datetime NOT NULL,
`note` varchar(255) DEFAULT NULL,
`location` enum('DIRECT') DEFAULT NULL,
`is_approved` enum('0','1') NOT NULL DEFAULT '1',
`idebit_issconf` varchar(50) DEFAULT NULL,
`idebit_issname` varchar(50) DEFAULT NULL,
`idebit_isstrack2` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `cus_id` (`cus_id`),
KEY `company_id` (`company_id`),
KEY `branch_admin_id` (`branch_admin_id`),
KEY `emp_id` (`emp_id`),
KEY `tran_id` (`tran_id`),
KEY `beehive_id` (`beehive_id`),
CONSTRAINT `customer_wallet_ibfk_1` FOREIGN KEY (`cus_id`) REFERENCES `customers` (`id`),
CONSTRAINT `customer_wallet_ibfk_2` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`),
CONSTRAINT `customer_wallet_ibfk_3` FOREIGN KEY (`tran_id`) REFERENCES `transaction` (`id`),
CONSTRAINT `customer_wallet_ibfk_4` FOREIGN KEY (`emp_id`) REFERENCES `employees` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=152 DEFAULT CHARSET=utf8
What you are doing as a correlated query on every wallet ID to get the corresponding debits and credits. It appears you are getting one record per wallet id. This is very busy. Having a join to the customer payments table on your criteria that is common (including the join per wallet id). Then, simplify the CASE as a SUM( case/when ) as respective debit / credit.
I don't know your underlying criteria of table columns, but I would even hedge to (and did) include NOT the CE_TYPE = 'IN' as that appears basis of a debit and you would not want to falsely count as part of a credit too. Again, dont know correlation of fields, trans_id, types.
Now, as stated, having individual indexes on individual fields will not help optimize this query. I would suggest the following indexes.
table index
customer_wallet ( company_id, is_approved, currency, id, date_added )
customer_payment_options ( wallet_id, account_type, country_id )
SELECT
cw.wallet_id,
SUM( case when cpo.ce_type = 'IN'
then cpo.payment_amount
ELSE 0 end ) as Debit,
SUM( case when NOT cpo.ce_type = 'IN'
AND cpo.tran_id IS NOT NULL
then cpo.payment_amount
ELSE 0 end ) as Credit
FROM
customer_wallet cw
JOIN customer_payment_options cpo
ON cw.id = cpo.wallet_id
AND cpo.real_account_type = 'HQ'
AND cpo.source_country_id = '40'
WHERE
cw.company_id = '1'
AND cw.currency = '40'
AND cw.is_approved = '1'
AND cw.date_added < '2016-03-30'
GROUP BY
cw.id
One additional comment. if your ID columns, Currency flag, country ID, approved are actually numeric values in the table structure, remove the quotes and let compare directly on the numeric value. Also, for your date_added. You had that based on DATE( date_added ). Doing a function on a column can not fully utilize the index. Since date() strips off any time portion of a date/time stamp column, and you are asking for all added less than Mar 30, then date added of March 29 # 11:59:59pm is still less than Mar 30 at 12:00:00am, so no date conversion is required.
As commented by Ivan (below), if you want ALL Wallet IDs regardless of having any payments (debit or credit), then change from a join to a LEFT JOIN.
You need to add indexes and multi-column indexes to make it fast.
Please keep in mind, that if you have large table, extra indexes will slow-down the insertions , since index file update will take more time.
If a multiple-column index exists on col1 and col2, the appropriate
rows can be fetched directly. If separate single-column indexes exist
on col1 and col2, the optimizer attempts to use the Index Merge
optimization (see Section 8.2.1.4, “Index Merge Optimization”), or
attempts to find the most restrictive index by deciding which index
excludes more rows and using that index to fetch the rows.
If the table has a multiple-column index, any leftmost prefix of the
index can be used by the optimizer to look up rows. For example, if
you have a three-column index on (col1, col2, col3), you have indexed
search capabilities on (col1), (col1, col2), and (col1, col2, col3).
Read more

MySQL - GROUP BY slow down the page

GROUP BY clause in the query below slow down the page, please help to resolve this issue
SELECT
`a`.*,
CONCAT(a.`firstname`, " ", a.`lastname`) AS `cont_name`,
CONCAT(a.`position`, " / ", a.`company`) AS `comp_pos`,
CONCAT(f.`firstname`, " ", f.`lastname`) AS `created_by`
FROM
`contacts` AS `a`
LEFT JOIN `users` AS `f` ON f.id = a.user_id
LEFT JOIN `user_centres` AS `b` ON a.user_id = b.user_id
WHERE b.centre_id IN (23, 24, 25, 26, 20, 21, 22, 27, 28)
GROUP BY `a`.`id`
ORDER BY `a`.`created` desc
Here the join with user_centres table is for centre wise filtering of data. EXPLAIN gives the result as:
- 1 SIMPLE a index PRIMARY,user_id,area_id,industry_id,country PRIMARY 4 NULL 20145 Using temporary; Using filesort
Our requirement is as below
Listing of all contacts in admin login
Centre wise listing of contacts in manager/clerk login
Total records in contact table is > 20K.
There will be multiple entry for users in user_centres table, ie: a user is assigned to more than one centre.
While executing the query in server by excluding GROUP BY is nearly 300k data which makes the problem.
Db stucture
Table structure for table contacts
CREATE TABLE IF NOT EXISTS `contacts` (
`id` int(11) NOT NULL,
`user_id` int(11) DEFAULT NULL,
`imported` tinyint(4) NOT NULL DEFAULT '0',
`situation` char(10) DEFAULT NULL,
`firstname` varchar(150) DEFAULT NULL,
`lastname` varchar(150) DEFAULT NULL,
`position` varchar(150) DEFAULT NULL,
`dob` datetime DEFAULT NULL,
`office_contact` varchar(100) DEFAULT NULL,
`mobile_contact` varchar(100) DEFAULT NULL,
`email` varchar(255) NOT NULL,
`company` varchar(150) DEFAULT NULL,
`industry_id` int(11) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
`city` varchar(150) DEFAULT NULL,
`country` int(11) DEFAULT NULL,
`isclient` tinyint(4) NOT NULL DEFAULT '0',
`classification` varchar(100) DEFAULT NULL,
`created` datetime NOT NULL,
`updated` datetime NOT NULL,
`unsubscribe` enum('Y','N') NOT NULL DEFAULT 'N'
) ENGINE=InnoDB AUTO_INCREMENT=25203 DEFAULT CHARSET=latin1;
Indexes for table contacts
ALTER TABLE `contacts`
ADD PRIMARY KEY (`id`), ADD KEY `user_id` (`user_id`),
ADD KEY `industry_id` (`industry_id`), ADD KEY `country` (`country`);
Constraints for table contacts
ALTER TABLE `contacts`
ADD CONSTRAINT `contacts_ibfk_4` FOREIGN KEY (`user_id`)
REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION,
ADD CONSTRAINT `contacts_ibfk_6` FOREIGN KEY (`industry_id`)
REFERENCES `industries` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION,
ADD CONSTRAINT `contacts_ibfk_7` FOREIGN KEY (`country`)
REFERENCES `country` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
Table structure for table users
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
`email` varchar(250) NOT NULL,
`password` varchar(45) NOT NULL,
`salt` varchar(45) DEFAULT NULL,
`status_id` int(11) DEFAULT NULL,
`status` tinyint(1) DEFAULT '1',
`firstname` varchar(255) NOT NULL,
`lastname` varchar(255) NOT NULL,
`created` datetime DEFAULT NULL,
`updated` datetime DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=latin1;
Indexes for table users
ALTER TABLE `users`
ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `email_UNIQUE` (`email`),
ADD KEY `type_id_idx` (`role_id`), ADD KEY `status_id_idx` (`status_id`);
Constraints for table users
ALTER TABLE `users`
ADD CONSTRAINT `role_id` FOREIGN KEY (`role_id`)
REFERENCES `users_roles` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `status_id` FOREIGN KEY (`status_id`)
REFERENCES `users_status` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `users_ibfk_1` FOREIGN KEY (`area`)
REFERENCES `area` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
Table structure for table user_centres
CREATE TABLE IF NOT EXISTS `user_centres` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`area_id` int(11) NOT NULL,
`centre_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=72 DEFAULT CHARSET=utf8;
Indexes for table user_centres
ALTER TABLE `user_centres`
ADD PRIMARY KEY (`id`), ADD KEY `user_id` (`user_id`),
ADD KEY `centre_id` (`centre_id`), ADD KEY `area_id` (`area_id`);
Constraints for table user_centres
ALTER TABLE `user_centres`
ADD CONSTRAINT `user_centres_ibfk_1` FOREIGN KEY (`user_id`)
REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
ADD CONSTRAINT `user_centres_ibfk_2` FOREIGN KEY (`centre_id`)
REFERENCES `centre` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION;
Also please refer EXPLAIN screens - http://prntscr.com/6o5h8s
Index were not used because of the different ORDER BY a GROUP BY clauses.
http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
You are spending a lot of time checking user_centres, but not needing anything from it. Remove it from the query.
users can be made into a correlates subquery:
SELECT `a`.*,
CONCAT(a.`firstname`, " ", a.`lastname`) AS `cont_name`,
CONCAT(a.`position`, " / ", a.`company`) AS `comp_pos`,
( SELECT CONCAT(f.`firstname`, " ", f.`lastname`)
FROM `users` AS `f` ON f.id = a.user_id
) AS `created_by`
FROM `contacts` AS `a`
GROUP BY `a`.`id`
ORDER BY `a`.`created` desc
Do you really need all 20K rows?? The sheer bulk of the result is part of the sluggishness.
Thanks all, based on the feedback got from all of you I have tried the query below now and give me the speed improvement from 30 secs to 15 secs
SELECT `a`.`id`, `a`.`user_id`, `a`.`imported`, `a`.`created`,
`a`.`unsubscribe`, CONCAT(a.firstname, " ", a.lastname) AS `cont_name`,
CONCAT(a.position, " / ", a.company) AS `comp_pos`,
( SELECT COUNT(uc.id)
FROM `user_centres` AS `uc`
WHERE (uc.user_id = a.user_id)
AND (uc.centre_id IN (29))
GROUP BY `uc`.`user_id`
) AS `centre_cnt`,
( SELECT GROUP_CONCAT(DISTINCT g.group_name
ORDER BY g.group_name ASC SEPARATOR ", ")
FROM `groups` AS `g`
INNER JOIN `group_contacts` AS `gc` ON g.id = gc.group_id
WHERE (gc.contact_id = a.id)
GROUP BY `gc`.`contact_id`
) AS `group_name`,
( SELECT CONCAT(u.`firstname`, " ", u.`lastname`)
FROM `users` AS `u`
WHERE (u.id = a.user_id)
) AS `created_by`, `e`.`name` AS `industry_name`
FROM `contacts` AS `a`
LEFT JOIN `industries` AS `e` ON e.id = a.industry_id
WHERE (1)
HAVING (centre_cnt is NOT NULL)
ORDER BY `a`.`id` desc
Let me know Is there a way to improve the speed and make the page loading below 5 secs.
Please see the interface (noted the filtering and sorting fields) - http://prntscr.com/6q6q70

multi table content selection

I am working on Exam System. I have (student),(student_test),(test),(departments) tables having relationship with each others. When every student log in there is a link called take test which will redirect them to take test page.
Question: How can I get all the available related to student department tests from test table only if the student have not attended the test or in other words how to get all the test from test table that student haven't taken?
$select=$connection->query("SELECT
student.std_id,
student.department,
test.depart_id,
test.test_id,
test.test_name,
test.test_from,
std_test.stdid,
std_test.std_test_id
FROM student
INNER JOIN test
ON student.department = test.depart_id
INNER JOIN std_test
ON std_test.std_test_id <> test.test_id
I tried this code as well but not results.
SELECT
student.std_id,
student.department,
test.depart_id,
test.test_id,
test.test_name,
test.test_from,
std_test.stdid,
std_test.std_test_id
FROM student
INNER JOIN test
ON student.department = test.depart_id
INNER JOIN std_test
ON std_test.std_test_id <> test.test_id
WHERE test.test_id <> std_test.std_test_id AND student.std_id <> std_test.stdid
Schema Script
CREATE TABLE student (
std_id int(11) NOT NULL AUTO_INCREMENT,
name varchar(50) NOT NULL,
f_name varchar(50) NOT NULL,
department int(11) NOT NULL,
semester varchar(255) NOT NULL,
pass varchar(255) NOT NULL,
email varchar(60) NOT NULL,
rollnumber varchar(20) NOT NULL,
PRIMARY KEY (std_id),
INDEX department (department),
UNIQUE INDEX email (email),
CONSTRAINT student_ibfk_1 FOREIGN KEY (department)
REFERENCES departments (dep_id) ON DELETE RESTRICT ON UPDATE RESTRICT
)
ENGINE = INNODB
AUTO_INCREMENT = 8
AVG_ROW_LENGTH = 8192
CHARACTER SET latin1
COLLATE latin1_swedish_ci;
CREATE TABLE test (
test_id int(11) NOT NULL AUTO_INCREMENT,
test_name varchar(80) NOT NULL,
test_date varchar(30) NOT NULL,
test_from datetime NOT NULL,
test_to datetime NOT NULL,
test_code varchar(30) NOT NULL,
test_conducter varchar(30) NOT NULL,
test_duration int(11) NOT NULL,
total_question int(11) NOT NULL,
session varchar(50) DEFAULT NULL,
subject_id int(11) NOT NULL,
semester_id int(11) NOT NULL,
depart_id int(11) NOT NULL,
status varchar(50) NOT NULL,
PRIMARY KEY (test_id),
INDEX depart_id (depart_id),
INDEX semester_id (semester_id),
INDEX subject_id (subject_id, semester_id, depart_id),
CONSTRAINT test_ibfk_1 FOREIGN KEY (subject_id)
REFERENCES subjects (id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT test_ibfk_2 FOREIGN KEY (semester_id)
REFERENCES semester (sem_id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT test_ibfk_3 FOREIGN KEY (depart_id)
REFERENCES departments (dep_id) ON DELETE CASCADE ON UPDATE CASCADE
)
ENGINE = INNODB
AUTO_INCREMENT = 6
AVG_ROW_LENGTH = 16384
CHARACTER SET latin1
COLLATE latin1_swedish_ci;
CREATE TABLE std_test (
stdid int(11) NOT NULL,
std_test_id int(11) NOT NULL,
starttime timestamp DEFAULT CURRENT_TIMESTAMP,
endtime timestamp DEFAULT '0000-00-00 00:00:00',
progress enum ('over', 'inprogress') NOT NULL,
PRIMARY KEY (std_test_id),
INDEX stdid (stdid),
INDEX tstid (std_test_id),
CONSTRAINT std_test_ibfk_2 FOREIGN KEY (std_test_id)
REFERENCES test (test_id) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT std_test_ibfk_3 FOREIGN KEY (stdid)
REFERENCES student (std_id) ON DELETE RESTRICT ON UPDATE RESTRICT
)
ENGINE = INNODB
AVG_ROW_LENGTH = 16384
CHARACTER SET latin1
COLLATE latin1_swedish_ci;
untested and shortened, but this is, what i understand, when i read your question
SELECT ....
FROM student s
INNER JOIN test t ON t.depart_id = s.department
LEFT JOIN std_test st ON t.test_id = st.std_test_id
WHERE st.stdid IS NULL
should work now

Optimizing sql statements to reduce MySQL server load

$sql1 = "SELECT questions FROM last_check_date WHERE user_id=? ORDER BY questions DESC LIMIT 1";
$sql2 = "SELECT id FROM questions WHERE add_dt>?";
What do statements above do?
When I execute sql1, it gets last check date for user.
Then I'm executing second query, to fetch all id's where add date>last check date (from sql1) and return affected rows count.
What I want to do is to merge this 2 statements into 1, and optimize query count. Following problem may occur:
There is no row for user in $sql1: must select all rows in sql2 and return affected rows count.
I can't figure out how it must look like.. Thx in advance
UPDATE
SHOW CREATE TABLE last_check_date; result is
CREATE TABLE `last_check_date` (
`id` int(11) unsigned NOT NULL,
`user_id` bigint(20) unsigned NOT NULL,
`questions` datetime DEFAULT NULL,
`users` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
And SHOW CREATE TABLE questions;
CREATE TABLE `questions` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`author_id` bigint(20) unsigned DEFAULT NULL,
`question` text NOT NULL,
`var_a` text NOT NULL,
`var_b` text NOT NULL,
`var_c` text NOT NULL,
`var_d` text NOT NULL,
`var_e` text NOT NULL,
`subject` int(11) unsigned DEFAULT NULL,
`chapter` int(11) unsigned DEFAULT NULL,
`section` int(11) unsigned DEFAULT NULL,
`paragraph` int(11) unsigned DEFAULT NULL,
`rank` tinyint(2) NOT NULL,
`add_dt` datetime NOT NULL,
`answer` varchar(1) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_chapters-id` (`chapter`),
KEY `fk_paragraphs-id` (`paragraph`),
KEY `fk_subjects-id` (`subject`),
KEY `fk_sections-id` (`section`),
KEY `fk_author-id` (`author_id`),
CONSTRAINT `fk_author-id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_chapters-id` FOREIGN KEY (`chapter`) REFERENCES `chapters` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_paragraphs-id` FOREIGN KEY (`paragraph`) REFERENCES `paragraphs` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_sections-id` FOREIGN KEY (`section`) REFERENCES `sections` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `fk_subjects-id` FOREIGN KEY (`subject`) REFERENCES `subjects` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
$sql = "
SELECT q.id
FROM questions q
LEFT JOIN (
SELECT questions
FROM last_check_date
WHERE user_id=?
ORDER BY questions
DESC LIMIT 1
) l ON q.add_dt > l.questions"
$rs = mysql_query($sql);
$rowcount = mysql_num_rows($rs);
I don't know yet the proper syntax for PDO/MYSQLI, please adapt to your prefered driver.
See below. I have assumed that if there are no records in last_check_date that you still want to show questions (in that case all of them).
select q.id
from questions q
left outer join (
select max(questions) as questions
from last_check_date
where user_id = ?
) lcd on q.add_date > lcd.questions
where user_id = ?
order by questions desc

Categories