need a little push with some query details - mysql

i have two tables "users" and "bookings"
and i need to count how many users have entered and registered by selected year and every month
and how many amount they have spent for the matched year and month
CREATE TABLE `users` (
`user_id` int(11) NOT NULL,
`user_name` varchar(255) DEFAULT NULL,
`user_nationality` varchar(255) DEFAULT NULL,
`user_birthYear` int(11) DEFAULT NULL,
`user_email` varchar(255) DEFAULT NULL,
`user_passportNumber` varchar(255) DEFAULT NULL,
`user_hotel` varchar(255) DEFAULT NULL,
`gender` varchar(255) NOT NULL,
`addedOn` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `users` (`user_id`, `user_name`, `user_nationality`, `user_birthYear`, `user_email`, `user_passportNumber`, `user_hotel`, `gender`, `addedOn`) VALUES
(104, 'john abraham', 'albania', 1994, 'john#john.com', '11100', 'google', 'male', '2023-01-29 09:06:41'),
(112, 'jah graz', 'morocco', 1990, 'jah#hah.com', '1843', 'df', 'male', '2023-02-06 17:29:58'),
(115, 'ronaldo abraham', 'angola', 1993, 'ronaldo#gmail.com', '87565', 'ng', 'male', '2023-02-06 17:30:42'),
(116, 'zhengjian yangben', 'china', 1983, 'gfjhfghfgh#ytfghj.com', 'e00000000', 'gt', 'female', '2023-02-06 17:30:56'),
(117, 'oksiao tiah', 'china', 1983, 'oksia#ytfghj.com', 'e000000001', 'google', 'female', '2023-02-06 17:31:26');
CREATE TABLE `bookings` (
`booking_id` int(11) NOT NULL,
`user_name` varchar(255) NOT NULL,
`user_birthYear` int(11) NOT NULL,
`user_nationality` varchar(255) NOT NULL,
`user_id` int(11) DEFAULT NULL,
`user_group` varchar(255) NOT NULL,
`place_id` text DEFAULT NULL,
`booked_by` int(11) DEFAULT NULL,
`booked_date` date NOT NULL,
`booked_on` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`booking_ref` varchar(255) DEFAULT NULL,
`amount` decimal(12,2) NOT NULL,
`status` int(11) DEFAULT NULL,
`isDomestic` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `bookings` (`booking_id`, `user_name`, `user_birthYear`, `user_nationality`, `user_id`, `user_group`, `place_id`, `booked_by`, `booked_date`, `booked_on`, `booking_ref`, `amount`, `status`, `isDomestic`) VALUES
(647, 'john abraham', 1994, 'albania', 104, 'adult', '36', 4, '2023-02-02', '2023-02-02 14:38:42', 'B-12167534871964719944', '200.00', 0, 'false'),
(648, 'zhengjian yangben', 1983, 'china', 116, 'adult', '36', 4, '2023-02-02', '2023-02-02 14:41:12', 'B-83167534874736719834', '300.00', 0, 'false'),
(649, 'zhengjian yangben', 1983, 'china', 104, 'adult', '37', 4, '2023-02-06', '2023-02-03 19:50:43', 'B-41167566360101919834', '100.00', 0, 'false'),
(650, 'john abraham', 1994, 'albania', 104, 'adult', '37', 4, '2023-02-06', '2023-02-06 06:07:03', 'B-41167566360101919834', '0.00', 0, 'false'),
(651, 'john abraham', 1994, 'albania', 116, 'adult', '37', 4, '2023-02-06', '2023-02-06 06:07:44', 'B-54167566365174419944', '0.00', 0, 'false'),
(652, 'zhengjian yangben', 1983, 'china', 116, 'adult', '37', 4, '2023-02-06', '2023-02-06 06:07:44', 'B-54167566365174419944', '0.00', 0, 'false'),
(653, 'john abraham', 1994, 'albania', 104, 'adult', '36', 4, '2023-02-02', '2023-02-02 14:38:42', 'B-12167534871964719944', '200.00', 0, 'false'),
(654, 'john abraham', 1994, 'albania', 104, 'adult', '36', 4, '2023-02-02', '2023-01-01 14:38:42', 'B-12167534871964719944', '200.00', 0, 'false');
here is what i have tried
first:
SELECT
`user_nationality` AS `Nationality`,
COUNT(`user_id`) AS `usersCount`,
MONTHNAME(`addedOn`) AS `monthName`,
MONTH(`addedOn`) AS `month`
FROM `users`
WHERE DATE_FORMAT(`addedOn`,'2023-%m') = DATE_FORMAT(`addedOn`,'2023-%m')
GROUP BY `monthName`,`Nationality`
ORDER BY `month`
from above code i can get the correct results, but i cant get the correct amount if i join bookings table
i need to join bookings table to get total amount for the matched country, year and month

I'm not going to answer specifically, instead, generically to help others. Follow this as a guide and translate this into what you need for your specific use case. But... before I get into the details. You are missing Primary Keys and Foreign Keys from the data model you have provided. Get your basics right.
Looks like you are working with some kind of hotel booking system. Imagine the scenario... you turn up at a hotel in real life, tell the receptionist you have a booking, they ask you your name, and you don't tell them.... You won't be passing reception. You data model is no different. Get the basics right and the rest falls into place.
Anyhow, you need something like this;
SELECT
main_table.id
, SUM(second_table.field_you_want_to_sum)
, MONTH(second_table.created_date)
, YEAR(second_table.created_date)
, CONCAT(YEAR(second_table.created_date), "-", MONTH(second_table.created_Date))
FROM
main_table
LEFT JOIN second_table ON main_table.id = second_table.main_table_id_fk
GROUP BY
main_table.id, CONCAT(YEAR(second_table.created_date), "-", MONTH(second_table.created_date))
;
SUM / COUNT, etc. Same concept in this context. You'll also probably want an ORDER BY in there too, hence why the CONCAT party is erring towards the yyyy-mm-dd format as this is how you need to structure things.
Update

Related

SQL Query to show documents for specific users when joined

I have created a document upload system, where an organisation will tell a user "you need to upload these X documents". Then the user gets an email, and can go to the profile page of that organisation and upload each of these documents in its corresponding upload form.
I have created 3 tables for this, vrm_document (this holds all the documents that are uploaded to the document system by organisations). vrm_document_user_link (this shows the documents linked from an organisation to a user). And vrm_document_user_upload (this holds the documents uploaded by the user to the organisation).
I cannot get my query right to show all the documents the user needs to upload together with the values whether it's uploaded already or not.
I have created a DBFiddle showing the query with the faulty data that is returning. In the example output of the DB Fiddle, the first row is returning a value for vrm_document_user_upload_id and document_path, while these are values for another user, but since the vrm_document_id matches, it shows these values here.
How do I solve this query?
This is the database structure I have created, together with the inserts:
CREATE TABLE vrm_document(
`vrm_document_id` INT(11) NOT NULL AUTO_INCREMENT,
`parent_vrm_document_id` INT(11) DEFAULT NULL,
`is_default_document` TINYINT(3) DEFAULT '0',
`country_id` INT(11) DEFAULT NULL COMMENT 'used only if document is a default document',
`user_id` INT(11) DEFAULT NULL COMMENT 'user id of who it is created for, null for default documents',
`user_auth_level` INT(11) DEFAULT NULL,
`title` VARCHAR(255) NOT NULL,
`version_name` VARCHAR(255) DEFAULT NULL,
`description` VARCHAR(255) DEFAULT NULL COMMENT 'empty for certain document types',
`vrm_document_type_id` INT(11) NOT NULL,
`document_preview` VARCHAR(255) NULL,
`document_preview_thumbnail` VARCHAR(255) NULL,
`document_path` VARCHAR(255) DEFAULT NULL,
`language_id` INT(11) DEFAULT NULL,
`timestamp_created_utc` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`timestamp_modified_utc` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_user_id` INT(11) DEFAULT NULL COMMENT 'the user id of who created the document',
`create_user_auth_level` INT(11) DEFAULT NULL,
`create_user_id_toggle` INT(11) DEFAULT NULL COMMENT 'user id of who was toggled to to create the document',
`create_user_auth_level_toggle` INT(11) DEFAULT NULL,
PRIMARY KEY (`vrm_document_id`)
) ENGINE = InnoDB;
CREATE TABLE vrm_document_user_upload(
`vrm_document_user_upload_id` INT(11) NOT NULL AUTO_INCREMENT,
`from_user_id` INT(11) NOT NULL,
`from_user_auth_level` INT(11) NOT NULL,
`to_user_id` INT(11) NOT NULL,
`to_user_auth_level` INT(11) NOT NULL,
`vrm_document_id` INT(11) NOT NULL,
`document_path` VARCHAR(255) NOT NULL,
`vrm_document_upload_status_id` INT(11) NOT NULL DEFAULT 0,
`reject_reason` VARCHAR(255) DEFAULT NULL,
`timestamp_uploaded_utc` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`create_user_id` INT(11) DEFAULT NULL COMMENT 'the user id of who uploaded the document',
`create_user_auth_level` INT(11) DEFAULT NULL,
`create_user_id_toggle` INT(11) DEFAULT NULL COMMENT 'user id of who was toggled to to upload the document',
`create_user_auth_level_toggle` INT(11) DEFAULT NULL,
PRIMARY KEY (`vrm_document_user_upload_id`)
) ENGINE = InnoDB;
CREATE TABLE vrm_document_user_link(
`from_user_id` INT(11) NOT NULL COMMENT 'the user id who attached the document to another user',
`to_user_id` INT(11) NOT NULL COMMENT 'the user id who the document is attached to',
`vrm_document_id` INT(11) NOT NULL,
FOREIGN KEY (`vrm_document_id`) REFERENCES `vrm_document` (`vrm_document_id`)
) ENGINE = InnoDB;
INSERT INTO `vrm_document` (`vrm_document_id`, `parent_vrm_document_id`, `is_default_document`, `country_id`, `user_id`, `user_auth_level`, `title`, `version_name`, `description`, `vrm_document_type_id`, `document_preview`, `document_preview_thumbnail`, `document_path`, `language_id`, `timestamp_created_utc`, `timestamp_modified_utc`, `create_user_id`, `create_user_auth_level`, `create_user_id_toggle`, `create_user_auth_level_toggle`) VALUES (1, NULL, 1, 19, NULL, NULL, 'Vrijwilligerscontract', 'Vrijwilligerscontract - Give a Day', 'Standaard vrijwilligerscontract aangeboden door Give a Day.', 2, NULL, NULL, '/vrm/documents/default_documents/180130_Uitnodiging_Aventi-in-beweging_v2.pdf', 14, '2020-03-27 14:53:19', '2020-03-27 14:53:19', NULL, NULL, NULL, NULL);
INSERT INTO `vrm_document` (`vrm_document_id`, `parent_vrm_document_id`, `is_default_document`, `country_id`, `user_id`, `user_auth_level`, `title`, `version_name`, `description`, `vrm_document_type_id`, `document_preview`, `document_preview_thumbnail`, `document_path`, `language_id`, `timestamp_created_utc`, `timestamp_modified_utc`, `create_user_id`, `create_user_auth_level`, `create_user_id_toggle`, `create_user_auth_level_toggle`) VALUES (9, NULL, 0, NULL, 2, 5, 'Nieuw doc als test', 'v1', 'Dit is een test', 2, NULL, NULL, 'vrm/documents/uploaded_documents/2020/03/template for evaluation of KBC Minimal Data Security requirements v2.0-DRAFT1-27032020163601.docx', 14, '2020-03-27 17:36:01', '2020-03-27 17:36:01', 1, 1, 2, 5);
INSERT INTO `vrm_document` (`vrm_document_id`, `parent_vrm_document_id`, `is_default_document`, `country_id`, `user_id`, `user_auth_level`, `title`, `version_name`, `description`, `vrm_document_type_id`, `document_preview`, `document_preview_thumbnail`, `document_path`, `language_id`, `timestamp_created_utc`, `timestamp_modified_utc`, `create_user_id`, `create_user_auth_level`, `create_user_id_toggle`, `create_user_auth_level_toggle`) VALUES (10, NULL, 0, NULL, 2, 5, 'Attest goed gedrag en zeden', '', 'Het attest van gedrag en goede zeden moet opgevraagd worden en terug opgeladen worden voor elke vrijwilliger die start bij ons. ', 3, NULL, NULL, NULL, 14, '2020-03-27 18:40:42', '2020-03-27 18:40:42', 1, 1, 2, 5);
INSERT INTO `vrm_document` (`vrm_document_id`, `parent_vrm_document_id`, `is_default_document`, `country_id`, `user_id`, `user_auth_level`, `title`, `version_name`, `description`, `vrm_document_type_id`, `document_preview`, `document_preview_thumbnail`, `document_path`, `language_id`, `timestamp_created_utc`, `timestamp_modified_utc`, `create_user_id`, `create_user_auth_level`, `create_user_id_toggle`, `create_user_auth_level_toggle`) VALUES (12, NULL, 0, NULL, 2, 5, 'test type 3', '', 'test voor type 3', 3, NULL, NULL, NULL, 14, '2020-03-31 07:19:14', '2020-03-31 07:19:14', 1, 1, 2, 5);
INSERT INTO `vrm_document` (`vrm_document_id`, `parent_vrm_document_id`, `is_default_document`, `country_id`, `user_id`, `user_auth_level`, `title`, `version_name`, `description`, `vrm_document_type_id`, `document_preview`, `document_preview_thumbnail`, `document_path`, `language_id`, `timestamp_created_utc`, `timestamp_modified_utc`, `create_user_id`, `create_user_auth_level`, `create_user_id_toggle`, `create_user_auth_level_toggle`) VALUES (64, NULL, 0, NULL, 2, 5, 'ooooooooo111', '', 'aezfs<wvcxcvw', 3, NULL, NULL, NULL, 14, '2020-04-03 12:21:06', '2020-04-03 12:21:06', 1, 1, 2, 5);
INSERT INTO `vrm_document_user_link` (`from_user_id`, `to_user_id`, `vrm_document_id`) VALUES (2, 24, 1);
INSERT INTO `vrm_document_user_link` (`from_user_id`, `to_user_id`, `vrm_document_id`) VALUES (2, 24, 9);
INSERT INTO `vrm_document_user_link` (`from_user_id`, `to_user_id`, `vrm_document_id`) VALUES (2, 24, 10);
INSERT INTO `vrm_document_user_link` (`from_user_id`, `to_user_id`, `vrm_document_id`) VALUES (2, 24, 12);
INSERT INTO `vrm_document_user_link` (`from_user_id`, `to_user_id`, `vrm_document_id`) VALUES (2, 24, 64);
INSERT INTO `vrm_document_user_upload` (`vrm_document_user_upload_id`, `from_user_id`, `from_user_auth_level`, `to_user_id`, `to_user_auth_level`, `vrm_document_id`, `document_path`, `vrm_document_upload_status_id`, `reject_reason`, `timestamp_uploaded_utc`, `create_user_id`, `create_user_auth_level`, `create_user_id_toggle`, `create_user_auth_level_toggle`) VALUES (5, 1, 1, 2, 5, 1, 'vrm/documents/user_uploaded_documents/2020/04/helpende-handen-werf-44-01042020125653-07042020162326.docx', 1, NULL, '2020-04-07 16:23:26', 1, 1, NULL, NULL);
And this is the Query I am trying to give me correct results:
SELECT vdul.*, vd.title, vd.description, vduu.vrm_document_user_upload_id, vduu.document_path
FROM vrm_document_user_link AS vdul
LEFT JOIN vrm_document_user_upload AS vduu ON vdul.vrm_document_id = vduu.vrm_document_id
LEFT JOIN vrm_document AS vd ON vdul.vrm_document_id = vd.vrm_document_id
WHERE vdul.from_user_id = 2
AND vdul.to_user_id = 24
AND vd.vrm_document_type_id != 1
Update second query after response from Balmar:
SELECT vdul.*, vd.title, vd.description, vduu.vrm_document_user_upload_id, vduu.document_path
FROM vrm_document_user_link AS vdul
LEFT JOIN vrm_document_user_upload AS vduu ON ((vdul.vrm_document_id = vduu.vrm_document_id) AND (vdul.from_user_id = 2 AND vdul.to_user_id = 24))
LEFT JOIN vrm_document AS vd ON vdul.vrm_document_id = vd.vrm_document_id
WHERE vd.vrm_document_type_id != 1
DB Fiddle link:
https://www.db-fiddle.com/f/f4es4LDfFE7HUMrnSPbJKw/0
Update DB fiddle to include the user_ids in the JOIN statement:
https://www.db-fiddle.com/f/f4es4LDfFE7HUMrnSPbJKw/2
You need to add the user IDs to the join condition, so you only get documents for the same users.
SELECT vdul.*, vd.title, vd.description, vduu.vrm_document_user_upload_id, vduu.document_path
FROM vrm_document_user_link AS vdul
LEFT JOIN vrm_document_user_upload AS vduu
ON vdul.vrm_document_id = vduu.vrm_document_id
AND vdul.to_user_id = vduu.to_user_id
AND vdul.from_user_id = vduu.from_user_id
LEFT JOIN vrm_document AS vd
ON vdul.vrm_document_id = vd.vrm_document_id
AND vd.vrm_document_type_id != 1
WHERE vdul.from_user_id = 2
AND vdul.to_user_id = 24

Query was working in MYSQL but not MYSQLI

My query was working in MYSQL but not in MYSQLI.
I'm selecting students that have done the pre AND post test.
SELECT
studid as Username,
prepoints as 'Fitness Assessment Points Grade',
end AS 'End-of-Line Indicator'
FROM
fittest, points
WHERE
YEAR(submitted) = '2017'
AND semester = 'summer2'
GROUP BY studid
HAVING
(MAX(prepost = 'pre' ) + MAX(prepost = 'post')) = 2 AND COUNT(DISTINCT prepost) = 2
Any ideas what changes need to be made to get it working again?
Here is some sample data:
CREATE TABLE `fittest` ( `id` int(11) NOT NULL, `submitted`
datetime DEFAULT NULL, `studid` varchar(100) DEFAULT NULL,
`semester` varchar(50) DEFAULT NULL, `instructor` varchar(30)
DEFAULT NULL, `course` enum('PHED 1164') DEFAULT NULL, `section`
enum('5001','5003','5005','5007','5009','5011','5013','5015','5017','5019','5021','5023','5025','5027','5029','5031','5033','5035','5037','5039','5041','5043','5045','5047','5049','5051','5053','5055','5057','5059','5061','5063','5065','5067','5069')
DEFAULT NULL, `age` varchar(50) DEFAULT NULL, `gender`
enum('m','f') DEFAULT NULL, `ethnicity` enum('Hispanic','African
American','Asian','White-Non Hispanic','Other') DEFAULT NULL,
`height` char(4) DEFAULT NULL, `weight` int(3) DEFAULT NULL,
`flexibility` int(2) DEFAULT NULL, `crunches` int(3) DEFAULT NULL,
`pushups` int(3) DEFAULT NULL, `treadtimemin` int(2) DEFAULT NULL,
`treadtimesec` int(2) NOT NULL, `treadhr` int(3) DEFAULT NULL,
`prepost` enum('pre','post') NOT NULL, `end` char(1) NOT NULL
DEFAULT '#' ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `fittest` (`id`, `submitted`, `studid`, `semester`,
`instructor`, `course`, `section`, `age`, `gender`, `ethnicity`,
`height`, `weight`, `flexibility`, `crunches`, `pushups`,
`treadtimemin`, `treadtimesec`, `treadhr`, `prepost`, `end`) VALUES
(17, '2017-01-02 21:55:33', 'slacker', 'spring', 'Tim', 'PHED 1164',
'5001', '32', 'm', NULL, '69.5', 155, NULL, 29, 34, 22, 15, 76, 'pre',
'#'), (16, '2017-01-02 21:31:34', 'bfun', 'spring', 'Tim', 'PHED
1164', '5001', '32', 'm', NULL, '69.5', 122, NULL, 37, 36, 18, 14, 76,
'post', '#'), (15, '2017-01-02 21:31:09', 'bfun', 'spring', 'Tim',
'PHED 1164', '5001', '32', 'm', NULL, '69.5', 129, NULL, 21, 20, 23,
14, 76, 'pre', '#'),
I just figured out the issue isn't with the query. It was with the input. All the input had post for the prepost value so there were no results that were showing. Thanks for your help.

Mysql self joining on max id returned from first table using groupby

I need a sql that uses self join on max id from first table. Please look at the following image of table. I am grouping the table by service_id but I need the last message of each group. So For service group 5 message count should be 3 and last_message should be thirdMsg5. I wrote a sql below everything else is fine but it is throwing an error in the case of self join. It can't recognize msgTbl1.last_message_id. I think I am calling it before preparing it. I need help to solve this problem what would be the best sql to solve this in one query? And if possible please provide me this query in laravel query builder format.
SELECT count(msgTbl1.id) as message_count,
max(msgTbl1.id) as last_message_id,
msgTbl1.body,
msgTbl2.body as last_message,
services.name as service_name
FROM messages msgTbl1
LEFT JOIN (SELECT id, body FROM messages) AS msgTbl2
ON msgTbl2.id = msgTbl1.last_message_id
LEFT JOIN services on services.id = msgTbl1.service_id
WHERE receiver_id = 4 AND read_user = 'no'
GROUP BY msgTbl1.service_id
sql for the message table
CREATE TABLE `messages` (
`id` int(11) UNSIGNED NOT NULL,
`sender_id` int(11) UNSIGNED DEFAULT NULL,
`receiver_id` int(11) UNSIGNED DEFAULT NULL,
`service_id` int(11) UNSIGNED NOT NULL,
`sender_type` enum('user','agent','admin') NOT NULL,
`receiver_type` enum('user','agent','admin') NOT NULL,
`body` text,
`files` varchar(500) DEFAULT NULL COMMENT 'serialize',
`new_notification` enum('no','yes') NOT NULL DEFAULT 'yes',
`read_user` enum('yes','no') NOT NULL DEFAULT 'no',
`read_agent` enum('yes','no') NOT NULL DEFAULT 'no',
`status` enum('active','archive','deleted') NOT NULL DEFAULT 'active',
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `messages` (`id`, `sender_id`, `receiver_id`, `service_id`, `sender_type`, `receiver_type`, `body`, `files`, `new_notification`, `read_user`, `read_agent`, `status`, `created_at`, `updated_at`) VALUES
(1, 22, 4, 5, 'user', 'agent', 'firstMsg5', NULL, 'yes', 'no', 'yes', 'active', '2016-03-24 00:00:00', '2016-04-12 05:40:28'),
(2, 22, 4, 5, 'user', 'agent', 'secondMsg5', NULL, 'yes', 'no', 'yes', 'active', '2016-03-24 00:00:00', '2016-04-12 05:40:31'),
(3, 22, 4, 9, 'user', 'agent', 'firstMsg9', NULL, 'yes', 'yes', 'yes', 'active', '2016-03-24 00:00:00', '2016-04-12 05:40:45'),
(4, 4, 4, 9, 'agent', 'user', 'secondMsg9', NULL, 'yes', 'yes', 'yes', 'active', '2016-03-24 00:00:00', '2016-04-12 05:40:56'),
(5, 22, 4, 5, 'user', 'agent', 'thirdMsg5', NULL, 'yes', 'yes', 'yes', 'active', '2016-03-24 00:00:00', '2016-04-12 05:41:08');
Try this:
SELECT message_count,
last_message_id,
msgTbl1.body,
services.name as service_name
FROM messages msgTbl1
INNER JOIN (
SELECT MAX(id) AS last_message_id, COUNT(*) AS message_count
FROM messages
WHERE read_user = 'no'
GROUP BY service_id) AS msgTbl2
ON msgTbl1.id = msgTbl2.last_message_id
LEFT JOIN services on services.id = msgTbl1.service_id
WHERE receiver_id = 4

MySQL - Selecting rows who's id is not present as a foreign key in another table

In my rails app I have two tables - device_ports and circuits. My goal is to get a list of device_ports whose id is not being used in the physical_port_id column of the circuits table.
I have done something similar before on other tables but here my query only returns one row when it should return 23 rows - there are 24 device ports for this device and one is in use.
select id, name, device_id, multiuse
from device_ports
where (device_id = 6 and multiuse = 1)
or device_ports.id not in (select physical_port_id from circuits)
So this query gets all multiuse ports (so even if the id was referenced in the foreign key, this row should still be returned) and should also get all rows where the device_id is 6 but is not referenced in circuits but only the multiuse row is being returned.
The result from the query is
id | name | device_id | multiuse
------------------------------------
268 | test-1 | 6 | 1
I did try to create an sql fiddle but the build just seems to timeout.
CREATE TABLE `device_ports` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`device_id` int(11) DEFAULT NULL,
`name` tinytext,
`speed` tinytext,
`multiuse` tinyint(1) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id` (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=291 DEFAULT CHARSET=latin1;
INSERT INTO `device_ports` (`id`, `device_id`, `name`, `speed`, `multiuse`, `created_at`, `updated_at`)
*emphasized text*VALUES
(1, 1, 'Test Device Port', '100', 0, NULL, NULL),
(2, 1, 'Test Port 2', '300', 1, NULL, NULL),
(289, 6, 'test-22', '100', 0, NULL, NULL),
(290, 6, 'test-23', '100', 0, NULL, NULL),
(288, 6, 'test-21', '100', 0, NULL, NULL),
(287, 6, 'test-20', '100', 0, NULL, NULL),
(286, 6, 'test-19', '100', 0, NULL, NULL),
(284, 6, 'test-17', '100', 0, NULL, NULL),
(285, 6, 'test-18', '100', 0, NULL, NULL),
(283, 6, 'test-16', '100', 0, NULL, NULL),
(282, 6, 'test-15', '100', 0, NULL, NULL),
(281, 6, 'test-14', '100', 0, NULL, NULL),
(280, 6, 'test-13', '100', 0, NULL, NULL),
(279, 6, 'test-12', '100', 0, NULL, NULL),
(278, 6, 'test-11', '100', 0, NULL, NULL),
(277, 6, 'test-10', '100', 0, NULL, NULL),
(276, 6, 'test-9', '100', 0, NULL, NULL),
(275, 6, 'test-8', '100', 0, NULL, NULL),
(274, 6, 'test-7', '100', 0, NULL, NULL),
(273, 6, 'test-6', '100', 0, NULL, NULL),
(272, 6, 'test-5', '100', 0, NULL, NULL),
(271, 6, 'test-4', '100', 0, NULL, NULL),
(270, 6, 'test-3', '100', 0, NULL, NULL),
(269, 6, 'test-2', '100', 0, NULL, NULL),
(268, 6, 'test-1', '100', 1, NULL, NULL),
(267, 6, 'test-0', '100', 0, NULL, NULL);
CREATE TABLE `circuits` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`organisation_id` int(11) DEFAULT NULL,
`physical_port_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=248 DEFAULT CHARSET=latin1;
INSERT INTO `circuits` (`id`, `organisation_id`, `physical_port_id`)
VALUES (1, 125, 267);
You could try using a LEFT OUTER JOIN:
SELECT DISTINCT d.id, d.name, d.device_id, d.multiuse
FROM device_ports d
LEFT OUTER JOIN circuits c ON c.physical_port_id = d.id
WHERE
(c.physical_port_id IS NULL AND d.device_id = 6)
OR (d.multiuse = 1 AND d.device_id = 6)
ORDER BY d.id
There are several techniques for this query, take a look at What's the difference between NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL?.
SELECT p.*
FROM device_ports p
LEFT
JOIN circuits c
ON c.physical_port_id = p.id
WHERE p.device_id = 6
AND multiuse = 1
AND c.id IS NULL;

CakePHP Subquery from SQL

CREATE TABLE IF NOT EXISTS `messages` (
`id` int(11) unsigned NOT NULL auto_increment,
`user_id` int(11) unsigned NOT NULL,
`node_id` int(11) unsigned NOT NULL,
`reciever_id` int(11) unsigned NOT NULL,
`created` datetime default NULL,
`modified` datetime default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;
INSERT INTO `messages` (`id`, `user_id`, `node_id`, `reciever_id`, `created`, `modified`) VALUES
(1, 1, 1, 15, '2011-12-07 00:00:00', '2011-12-07 02:00:00'),
(2, 15, 1, 1, '2011-12-07 02:00:00', '2011-12-07 02:00:00'),
(3, 15, 2, 1, '2011-12-07 11:00:00', '2011-12-07 11:00:00'),
(4, 1, 2, 15, '2011-12-07 11:00:00', '2011-12-07 11:00:00'),
(5, 1, 3, 18, '2011-12-07 11:00:00', '2011-12-07 11:00:00'),
(6, 18, 3, 1, '2011-12-07 11:00:00', '2011-12-07 11:00:00'),
(7, 1, 4, 18, '2011-12-07 12:00:00', '2011-12-07 12:00:00'),
(8, 18, 4, 1, '2011-12-07 12:00:00', '2011-12-07 12:00:00');
CREATE TABLE IF NOT EXISTS `nodes` (
`id` int(11) unsigned NOT NULL auto_increment,
`message` text NOT NULL,
`author_id` int(11) unsigned NOT NULL,
`read` tinyint(1) default NULL,
`created` datetime default NULL,
`modified` datetime default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
INSERT INTO `nodes` (`id`, `message`, `author_id`, `read`, `created`, `modified`) VALUES
(1, 'Hi! How are you ? dude wanna meet up this weekend ?', 1, 0, '2011-12-07 02:00:00', '2011-12-07 02:00:00'),
(2, 'Sure. wanna go to Mangalore Pearl to eat Neer Dosa..', 15, 0, '2011-12-07 11:00:00', '2011-12-07 11:00:00'),
(3, 'Hi How are u Buddy ? Long time no see...', 1, 0, '2011-12-07 11:00:00', '2011-12-07 11:00:00'),
(4, 'yeah. are you back in town ? i think we should meet up man. its been ages ....', 18, 0, '2011-12-07 12:00:00', '2011-12-07 12:00:00');
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) unsigned NOT NULL auto_increment,
`first_name` varchar(255) default NULL,
`last_name` varchar(255) default NULL,
`email` varchar(255) default NULL,
`password` varchar(40) default NULL,
`username` varchar(255) default NULL,
`birthday` date default NULL,
`gender` varchar(255) default NULL,
`city_id` int(11) unsigned NOT NULL,
`status` varchar(255) NOT NULL,
`created` datetime default NULL,
`modified` datetime default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=21 ;
I am trying to create a subquery in Cake. but not sure how to start :(
This is the SQL i want to execute
SELECT *
FROM (
SELECT *
FROM messages AS msg
WHERE user_id =1
ORDER BY modified DESC
) AS latest_message
GROUP BY reciever_id
Is it better to use sub Queries or write SQL statement ?
I'm not really sure what the necessity for a subquery is here, wouldn't something like this do the trick?
$this->Message->find('all', array(
'conditions' => array('Message.user_id' => 1),
'order' => array('Message.modified' => 'DESC'),
'group' => array('Message.receiver_id')
));
This would retrieve all the messages from the user with id 1, ordered by date modified and grouped by receiver_id.
Since you are trying to group by the receiver, then why not alter the query to retrieve the receivers and then the messages that belong to each one? Below, I am assuming use of the containable behavior.
$this->Receiver->find('all', array(
'contain' => array(
'Message' => array(
'conditions' => array('Message.user_id' => 1),
'order' => array('Message.modified' => 'DESC'),
)
)
));
EDIT
I added this query to see if it helps based on your comment.
$this->Message->find(
'all',
array(
'conditions' => array('Message.user_id' => 1),
'fields' => array('Message.*', 'MAX(Message.modified) as max_mod'),
'group' => 'Message.receiver_id'
)
);