MySQL/Mariadb problem: `Order by DESC` before `Group by` - mysql
Summary: I want to Order by before Group
I find a nice article about the problem, but finally not successful to fix it.
https://eddies-shop.medium.com/mysql-when-to-order-before-group-13d54d6c4ebb
My Server config:
Server type: MariaDB
Server version: 10.6.4-MariaDB - Arch Linux
About the query: I get a list of rooms and messages, but I only need the latest message for each room.
so I need to group by conversation_id, and sort by message_id or message_time.
The above query works well but is not complete.
In that, for each room, we have duplicate rows.
When I try and uncomment the last line from the query
And when I try to apply GROUP BY main.conversation_id. It is no longer in order and the order is broken again.
My Query:
SELECT
main.*
FROM
(
SELECT
sub.*
FROM
(
SELECT
conversation.id AS conversation_id,
CONCAT(user2.first_name, " ", user2.last_name) AS conversation_name,
conversation.is_group AS conversation_isgroup,
(SELECT user_id FROM conversation_member WHERE conversation_id = conversation.id AND user_id != 1) AS conversation_owner_id,
message.id AS message_id,
message.type AS message_type,
message.body AS message_body,
message.filename AS message_filename,
message.created_at AS message_time,
message.user_id AS message_user_id,
CONCAT(user.first_name, " ", user.last_name) AS message_user_name
FROM
conversation
INNER JOIN
conversation_member
ON
conversation_member.conversation_id = conversation.id
LEFT JOIN
message
ON
message.conversation_id = conversation.id
LEFT JOIN
user
ON
user.id = message.user_id
LEFT JOIN
user as user2
ON
user2.id = conversation.owner2_id
OR
user2.id = conversation.owner_id
WHERE
user2.id != 1
AND
name IS NULL
AND
conversation_member.user_id = 1
AND
conversation.is_group = 0
) AS sub
ORDER BY
sub.message_id DESC
) as main
# GROUP BY
# main.conversation_id
If you need to know more about the Database structure:
--
-- Table structure for table `conversation`
--
CREATE TABLE `conversation` (
`id` int(50) NOT NULL,
`name` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`owner_id` int(50) NOT NULL,
`owner2_id` int(50) DEFAULT NULL,
`is_group` int(2) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `conversation`
--
INSERT INTO `conversation` (`id`, `name`, `owner_id`, `owner2_id`, `is_group`, `created_at`, `updated_at`) VALUES
(7, 'تالار گفتگوی ریاضی', 1, NULL, 1, '2021-09-13 20:33:38', NULL),
(8, NULL, 2, 1, 0, '2021-09-13 20:33:46', '2021-09-14 07:55:44'),
(9, 'گروه ازمایشی', 3, NULL, 1, '2021-09-14 07:45:04', NULL),
(10, 'پروژه ها و ایده ها', 3, NULL, 1, '2021-09-14 07:47:19', NULL),
(11, NULL, 4, 1, 0, '2021-09-14 08:05:11', NULL);
--
-- Table structure for table `conversation_member`
--
CREATE TABLE `conversation_member` (
`id` int(50) NOT NULL,
`conversation_id` int(50) NOT NULL,
`user_id` int(50) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `conversation_member`
--
INSERT INTO `conversation_member` (`id`, `conversation_id`, `user_id`, `created_at`) VALUES
(1, 8, 1, '2021-09-14 07:02:18'),
(2, 8, 2, '2021-09-14 07:02:18'),
(3, 7, 1, '2021-09-14 07:02:28'),
(4, 7, 3, '2021-09-14 07:02:28'),
(5, 9, 3, '2021-09-14 07:45:13'),
(7, 10, 4, '2021-09-14 08:02:57'),
(8, 10, 2, '2021-09-14 08:02:57'),
(9, 10, 1, '2021-09-14 08:03:05'),
(10, 11, 4, '2021-09-14 08:05:23'),
(11, 11, 1, '2021-09-14 08:05:23'),
(12, 7, 4, '2021-09-14 09:30:04');
--
-- Table structure for table `message`
--
CREATE TABLE `message` (
`id` int(50) NOT NULL,
`conversation_id` int(50) NOT NULL,
`user_id` int(50) DEFAULT NULL,
`type` int(2) NOT NULL COMMENT '0=system,1=message,1=file,2=voice',
`body` text COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`filename` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`is_group` int(2) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`edited_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `message`
--
INSERT INTO `message` (`id`, `conversation_id`, `user_id`, `type`, `body`, `filename`, `is_group`, `created_at`, `edited_at`) VALUES
(1, 7, 1, 1, '1', NULL, 1, '2021-09-14 07:16:12', '2021-09-14 14:14:44'),
(2, 8, 1, 1, '2', NULL, 0, '2021-09-14 07:16:25', '2021-09-14 14:14:45'),
(3, 11, 1, 1, '3', NULL, 0, '2021-09-14 13:21:30', '2021-09-14 14:14:47'),
(4, 10, 1, 1, '4', NULL, 1, '2021-09-14 13:23:34', '2021-09-14 14:14:49'),
(5, 7, 1, 1, '5', NULL, 1, '2021-09-14 13:25:16', '2021-09-14 14:14:51'),
(6, 7, 1, 1, '6', NULL, 1, '2021-09-14 13:30:40', '2021-09-14 14:14:52'),
(7, 7, 1, 1, '7', NULL, 1, '2021-09-14 13:49:29', '2021-09-14 14:14:54'),
(8, 7, 1, 1, '8', NULL, 1, '2021-09-14 13:49:34', '2021-09-14 14:14:56'),
(9, 10, 1, 1, '9', NULL, 1, '2021-09-14 13:54:04', '2021-09-14 14:14:57'),
(10, 7, 1, 1, '10', NULL, 1, '2021-09-14 14:01:18', '2021-09-14 14:14:59'),
(11, 8, 1, 1, '11', NULL, 0, '2021-09-14 14:07:48', '2021-09-14 14:15:03'),
(12, 11, 4, 1, 'test-new', NULL, 0, '2021-09-14 15:11:51', NULL),
(13, 11, 1, 1, 'fdgdfg', NULL, 0, '2021-09-14 13:21:30', '2021-09-14 14:14:47'),
(14, 11, 1, 1, 'sd1f23sd1f', NULL, 0, '2021-09-14 15:33:02', NULL),
(15, 11, 1, 1, 'dfgdfgdfgdfg', NULL, 0, '2021-09-14 15:33:02', NULL),
(16, 11, 1, 1, 'dfgdfgdfg', NULL, 0, '2021-09-14 15:33:06', NULL),
(17, 11, 1, 1, 'dfg345345345', NULL, 0, '2021-09-14 15:33:06', NULL),
(18, 11, 1, 1, 'gdfg234234234', NULL, 0, '2021-09-14 15:33:17', NULL),
(19, 11, 1, 1, 'dfgda1323123f', NULL, 0, '2021-09-14 15:33:17', NULL),
(20, 11, 1, 1, '234234234234', NULL, 0, '2021-09-14 15:33:17', NULL),
(21, 11, 1, 1, '345345345345', NULL, 0, '2021-09-14 15:33:17', NULL),
(22, 11, 1, 1, '5565656', NULL, 0, '2021-09-14 15:33:17', NULL),
(23, 11, 1, 1, '7787878', NULL, 0, '2021-09-14 15:33:17', NULL),
(24, 11, 1, 1, 'یبلیبلیبلیبل', NULL, 0, '2021-09-14 15:33:28', NULL),
(25, 11, 1, 1, 'ض۳۲ث۱۲۳۴۲۳۴۲۳۴', NULL, 0, '2021-09-14 15:33:28', NULL),
(26, 11, 1, 1, '۳۴۵سیبیلبیبلب', NULL, 0, '2021-09-14 15:33:28', NULL),
(27, 11, 1, 1, 'فقفثفثقفثقف', NULL, 0, '2021-09-14 15:33:28', NULL),
(28, 11, 1, 1, '۳۳۴۲۴۲۳۴', NULL, 0, '2021-09-14 15:33:28', NULL),
(29, 11, 1, 1, '$$$$', NULL, 0, '2021-09-14 15:33:28', NULL),
(30, 11, 1, 1, '$$$%%dfgdfg', NULL, 0, '2021-09-14 15:33:47', NULL),
(31, 11, 1, 1, 'dfgdfg23423423423سیبلیبل', NULL, 0, '2021-09-14 15:33:47', NULL),
(32, 11, 1, 1, 'یبلص۴۳۵۲۳۴۵۳۴۵۳۴۵', NULL, 0, '2021-09-14 15:33:47', NULL),
(33, 11, 1, 1, 'یبل۳۵۳۴۵فثقیبلیبلیبل', NULL, 0, '2021-09-14 15:33:47', NULL),
(34, 11, 1, 1, 'یبلیلبل۳۴۵۳۴۵۳۴۵۳۴۵۳۴۵', NULL, 0, '2021-09-14 15:33:47', NULL),
(35, 11, 1, 1, '$$$$$####', NULL, 0, '2021-09-14 15:33:47', NULL);
--
-- Table structure for table `message_view`
--
CREATE TABLE `message_view` (
`id` int(50) NOT NULL,
`message_id` int(50) NOT NULL,
`conversation_id` int(50) NOT NULL,
`is_group` int(2) NOT NULL,
`user_id` int(50) NOT NULL,
`viewed_at` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `session`
--
CREATE TABLE `session` (
`id` int(50) NOT NULL,
`user_id` int(50) NOT NULL,
`device` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL,
`code` int(10) DEFAULT NULL,
`secret` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `session`
--
INSERT INTO `session` (`id`, `user_id`, `device`, `code`, `secret`) VALUES
(1, 1, '08ad5559-15f7-4c32-ab2d-2d8a563670a3', 0, '1'),
(2, 1, 'c8216675-08ff-4deb-9341-2afbe88bc716', NULL, '41234'),
(3, 1, 'f20279f4-615d-4b6f-83e4-0e6c201395e3', 53741, NULL),
(4, 1, 'bef6f3e2-04b7-4ff5-b948-c035c376f4d2', 51003, NULL),
(5, 1, '3492d860-6ae4-4a00-a65d-346d880c4e71', 30646, NULL),
(6, 1, 'fd0b2d35-d7aa-4e40-b362-6b592dc17aad', 28576, NULL),
(7, 1, 'c69516b4-53a8-4e69-a874-a11d859b451d', 32440, NULL),
(8, 1, '075149a4-d94c-4246-99ce-d0b71c72f26c', 99800, NULL),
(9, 1, '4804b854-89b6-4c85-8df3-815ffdd34fba', 19774, NULL),
(10, 1, 'a60195ac-2e50-42ed-9d71-1d3d04729339', 10262, NULL),
(11, 1, '80a9a2e7-ee8b-47ef-8ca4-75216721a6ac', 88424, 'bc82131e-0e59-4841-98b7-798cf65d9fcb'),
(12, 1, '6c120179-312f-4d73-9488-7f692cb54234', 42832, NULL),
(13, 1, 'a8b7ca5b-a47d-48b0-afeb-197b5ec7dc44', 39034, 'fdd51fe1-5bae-424f-9515-1a1b435faed6'),
(14, 1, '0652aa2a-01df-497d-b7b2-77fc87a29c24', 36133, '8fc206e1-1a49-444b-bcb6-ea289c17a918'),
(15, 1, '6b0bf6b9-4d32-4c6b-9e84-fd0b393acb31', 87972, '05de4b7a-cc6e-4ff0-b321-72473ac903bd'),
(16, 1, '0a523464-89ab-4f4a-803e-ca252e637e4f', 40843, 'a35a2169-949d-4043-a061-1a56ec30440e'),
(17, 1, '34b2e1bf-a088-48e8-85b8-1943db001fd5', 65916, '971a3cea-8ccc-45bf-887e-7797e4c6ab22'),
(18, 1, 'fcdb6c98-d044-43e8-a373-351f7ca1536d', 82257, 'bacb442d-e066-4117-a380-c468316d47f2'),
(19, 1, '565a036d-c4f8-46b0-8493-e5371e3dccca', 71626, '610b4e81-cf72-4091-a711-d64c601e0f0c'),
(20, 1, '8775a2d9-4544-48c4-ab5c-6d7216c955f7', 46912, 'b5eabb83-e372-4e7b-a48a-3c99eaba5d6d'),
(21, 1, 'a94f734b-0aa0-4ee9-aea3-86e2a405cf56', 44508, '2db51630-e32a-4172-90aa-99d5f7b00063'),
(22, 1, 'b0ed316b-483b-47cc-b27f-2fe6b83f410a', 87850, 'f68377a4-3ed8-4c36-8a78-1d807ed50449'),
(23, 1, '08f38458-cd12-4a9c-9c63-9c6aa291956b', 79266, 'e6314070-8401-4d7b-b9d7-a44c147c75ec'),
(24, 4, '192dfd3f-b2d7-401f-bf95-2d663b6badab', 65088, '6fa66aa9-f47d-46fd-9ce5-9645802383da'),
(25, 4, 'fc8fe94b-f220-42db-ab77-74de994f8275', 37715, '0e188502-67c2-44a9-b68c-32b07fa150ab'),
(26, 1, '27451de6-c730-450a-b76c-3ea53ff74580', 16934, '662ae741-fa42-4fc3-b0bb-5ae6c9e67b52'),
(27, 4, '6ba92f55-cffe-4d9e-b646-be9cf07e99e3', 91683, '27b85d09-831d-41cd-8032-17743a76616d');
--
-- Table structure for table `user`
--
CREATE TABLE `user` (
`id` int(50) NOT NULL,
`first_name` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`last_name` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`country_code` int(2) NOT NULL,
`phone_number` varchar(13) COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `user`
--
INSERT INTO `user` (`id`, `first_name`, `last_name`, `country_code`, `phone_number`, `created_at`, `updated_at`) VALUES
(1, 'Max', 'Base', 98, '9134458080', '2021-09-13 18:28:47', '2021-09-14 07:13:21'),
(2, 'Ali', 'Tahmasebi', 98, '91032545254', '2021-09-14 07:02:46', '2021-09-14 08:02:24'),
(3, 'B.', 'KheirKhah', 98, '9124554020', '2021-09-14 07:02:46', '2021-09-14 08:03:20'),
(4, 'H.', 'Malekian', 98, '9134550773', '2021-09-14 07:25:21', '2021-09-14 08:02:35');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `conversation`
--
ALTER TABLE `conversation`
ADD PRIMARY KEY (`id`),
ADD KEY `owner_id` (`owner_id`),
ADD KEY `is_group` (`is_group`);
--
-- Indexes for table `conversation_member`
--
ALTER TABLE `conversation_member`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `message`
--
ALTER TABLE `message`
ADD PRIMARY KEY (`id`),
ADD KEY `is_group` (`is_group`),
ADD KEY `user_id` (`user_id`),
ADD KEY `conversation_id` (`conversation_id`);
--
-- Indexes for table `message_view`
--
ALTER TABLE `message_view`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `session`
--
ALTER TABLE `session`
ADD PRIMARY KEY (`id`),
ADD KEY `user_id` (`user_id`),
ADD KEY `device` (`device`);
--
-- Indexes for table `user`
--
ALTER TABLE `user`
ADD PRIMARY KEY (`id`),
ADD KEY `phone_number` (`phone_number`),
ADD KEY `country_code` (`country_code`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `conversation`
--
ALTER TABLE `conversation`
MODIFY `id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12;
--
-- AUTO_INCREMENT for table `conversation_member`
--
ALTER TABLE `conversation_member`
MODIFY `id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=13;
--
-- AUTO_INCREMENT for table `message`
--
ALTER TABLE `message`
MODIFY `id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12;
--
-- AUTO_INCREMENT for table `message_view`
--
ALTER TABLE `message_view`
MODIFY `id` int(50) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `session`
--
ALTER TABLE `session`
MODIFY `id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=28;
--
-- AUTO_INCREMENT for table `user`
--
ALTER TABLE `user`
MODIFY `id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
COMMIT;
A bit more about the database and tables:
Purpose of conversation, conversation_member table: I have a database to store messenger data. there are 2 model conversations:
1: Group: multi people
2: Personal chat: a user to another user (It's why I have owner2_id column.)
And the main query is this to merge personal chat and group chats of user who ID = 1:
(
SELECT
sub1.*
FROM
(
SELECT
conversation.id AS conversation_id,
conversation.name AS conversation_name,
conversation.is_group AS conversation_isgroup,
conversation.owner_id AS conversation_owner_id,
message.id AS message_id,
message.type AS message_type,
message.body AS message_body,
message.filename AS message_filename,
message.created_at AS message_time,
message.user_id AS message_user_id,
CONCAT(user.first_name, " ", user.last_name) AS message_user_name
FROM
conversation
INNER JOIN
conversation_member
ON
conversation_member.conversation_id = conversation.id
LEFT JOIN
message
ON
message.conversation_id = conversation.id
LEFT JOIN
user
ON
user.id = message.user_id
WHERE
conversation_member.user_id = 1
AND
conversation.is_group = 1
) AS sub1
GROUP BY sub1.message_id desc
)
UNION
(
SELECT
sub2.*
FROM
(
SELECT
conversation.id AS conversation_id,
CONCAT(user2.first_name, " ", user2.last_name) AS conversation_name,
conversation.is_group AS conversation_isgroup,
(SELECT user_id FROM conversation_member WHERE conversation_id = conversation.id AND user_id != 1) AS conversation_owner_id,
message.id AS message_id,
message.type AS message_type,
message.body AS message_body,
message.filename AS message_filename,
message.created_at AS message_time,
message.user_id AS message_user_id,
CONCAT(user.first_name, " ", user.last_name) AS message_user_name
FROM
conversation
INNER JOIN
conversation_member
ON
conversation_member.conversation_id = conversation.id
LEFT JOIN
message
ON
message.conversation_id = conversation.id
LEFT JOIN
user
ON
user.id = message.user_id
LEFT JOIN
user as user2
ON
user2.id = conversation.owner2_id
OR
user2.id = conversation.owner_id
WHERE
user2.id != 1
AND
name IS NULL
AND
conversation_member.user_id = 1
AND
conversation.is_group = 0
) AS sub2
GROUP BY sub2.message_id desc
);
WHAT I'M DOING
I want a list of all group conversations and personal conversations and the last messages in that room and sort all of the rooms by last MESSAGE_TIME.
This is what happens to almost all messengers.
I will only use the query on your question to show how MariaDB deal with the order by in subquery.
I changed your user table with user01 because I had a table user in my MariaDB database.
SELECT
main.*
FROM
(
SELECT
sub.*
FROM
(
SELECT
conversation.id AS conversation_id,
CONCAT(user2.first_name, " ", user2.last_name) AS conversation_name,
conversation.is_group AS conversation_isgroup,
(SELECT user_id FROM conversation_member WHERE conversation_id = conversation.id AND user_id != 1) AS conversation_owner_id,
message.id AS message_id,
message.type AS message_type,
message.body AS message_body,
message.filename AS message_filename,
message.created_at AS message_time,
message.user_id AS message_user_id,
CONCAT(user01.first_name, " ", user01.last_name) AS message_user_name
FROM
conversation
INNER JOIN
conversation_member
ON
conversation_member.conversation_id = conversation.id
LEFT JOIN
message
ON
message.conversation_id = conversation.id
LEFT JOIN
user01
ON
user01.id = message.user_id
LEFT JOIN
user01 as user2
ON
user2.id = conversation.owner2_id
OR
user2.id = conversation.owner_id
WHERE
user2.id != 1
AND
name IS NULL
AND
conversation_member.user_id = 1
AND
conversation.is_group = 0
) AS sub
ORDER BY
sub.message_id DESC limit 10
) as main
GROUP BY
main.conversation_id;
I only added limit 10 on sub.message_id DESC limit 10 .
A "table" (and subquery in the FROM clause too) is - according to the
SQL standard - an unordered set of rows. Rows in a table (or in a
subquery in the FROM clause) do not come in any specific order. That's
why the optimizer can ignore the ORDER BY clause that you have
specified. In fact, the SQL standard does not even allow the ORDER BY
clause to appear in this subquery (we allow it, because ORDER BY ...
LIMIT ... changes the result, the set of rows, not only their order).
You need to treat the subquery in the FROM clause, as a set of rows in
some unspecified and undefined order, and put the ORDER BY on the
top-level SELECT
https://mariadb.com/kb/en/why-is-order-by-in-a-from-subquery-ignored/
I am not a master in SQL, by the way, I just success to fix the problem of one query after hours!
If you have an any better queries for this purpose, please post and answer.
This is only for one query, I have two queries and need to UNION and merge.
A single query:
SELECT
main.*
FROM
(
SELECT
sub.*
FROM
(
SELECT
conversation.id AS conversation_id,
CONCAT(user2.first_name, " ", user2.last_name) AS conversation_name,
conversation.is_group AS conversation_isgroup,
(SELECT user_id FROM conversation_member WHERE conversation_id = conversation.id AND user_id != 1) AS conversation_owner_id,
message.id AS message_id,
message.type AS message_type,
message.body AS message_body,
message.filename AS message_filename,
message.created_at AS message_time,
message.user_id AS message_user_id,
CONCAT(user.first_name, " ", user.last_name) AS message_user_name
FROM
conversation
INNER JOIN
conversation_member
ON
conversation_member.conversation_id = conversation.id
LEFT JOIN
message
ON
message.conversation_id = conversation.id
LEFT JOIN
user
ON
user.id = message.user_id
LEFT JOIN
user as user2
ON
user2.id = conversation.owner2_id
OR
user2.id = conversation.owner_id
WHERE
user2.id != 1
AND
name IS NULL
AND
conversation_member.user_id = 1
AND
conversation.is_group = 0
) AS sub
GROUP BY sub.message_id desc
) as main
GROUP BY main.conversation_id
Main query and UNION to merge the results:
(
SELECT
mm.*
FROM
(
(
SELECT
sub1.*
FROM
(
SELECT
conversation.id AS conversation_id,
conversation.name AS conversation_name,
conversation.is_group AS conversation_isgroup,
conversation.owner_id AS conversation_owner_id,
message.id AS message_id,
message.type AS message_type,
message.body AS message_body,
message.filename AS message_filename,
message.created_at AS message_time,
message.user_id AS message_user_id,
CONCAT(user.first_name, " ", user.last_name) AS message_user_name
FROM
conversation
INNER JOIN
conversation_member
ON
conversation_member.conversation_id = conversation.id
LEFT JOIN
message
ON
message.conversation_id = conversation.id
LEFT JOIN
user
ON
user.id = message.user_id
WHERE
conversation_member.user_id = 1
AND
conversation.is_group = 1
) AS sub1
GROUP BY sub1.message_id desc
)
UNION
(
SELECT
sub2.*
FROM
(
SELECT
conversation.id AS conversation_id,
CONCAT(user2.first_name, " ", user2.last_name) AS conversation_name,
conversation.is_group AS conversation_isgroup,
(SELECT user_id FROM conversation_member WHERE conversation_id = conversation.id AND user_id != 1) AS conversation_owner_id,
message.id AS message_id,
message.type AS message_type,
message.body AS message_body,
message.filename AS message_filename,
message.created_at AS message_time,
message.user_id AS message_user_id,
CONCAT(user.first_name, " ", user.last_name) AS message_user_name
FROM
conversation
INNER JOIN
conversation_member
ON
conversation_member.conversation_id = conversation.id
LEFT JOIN
message
ON
message.conversation_id = conversation.id
LEFT JOIN
user
ON
user.id = message.user_id
LEFT JOIN
user as user2
ON
user2.id = conversation.owner2_id
OR
user2.id = conversation.owner_id
WHERE
user2.id != 1
AND
name IS NULL
AND
conversation_member.user_id = 1
AND
conversation.is_group = 0
) AS sub2
GROUP BY sub2.message_id desc
)
) AS mm
GROUP BY mm.conversation_id desc
)
;
I am not sure the query is optimized or good.
but this works.
please review and comment on my query if this is not good enough.
Related
How to create dynamic columns using prepared statements in MySQL?
I have 4 tables related to each other. CREATE TABLE `location` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO `location` (`id`, `name`) VALUES (1, 'Dallas'), (2, 'Boston'), (3, 'Houston'); CREATE TABLE `item` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `brand` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO `item` (`id`, `brand`) VALUES (1, 'Nissan Almera M/T 2009-2015'), (2, 'Toyota Corolla A/T 2005-2012'), (3, 'Nissan Terra A/T 2010-2017'), (4, 'Suzuki Esteem M/T 1980-1990'), (5, 'Toyota Fortuner A/T 2014-2020'); CREATE TABLE `item_in` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `location_id` bigint(20) UNSIGNED NOT NULL, `item_id` bigint(20) UNSIGNED NOT NULL, `quantity` int(11) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO `item_in` (`id`, `location_id`, `item_id`, `quantity`) VALUES (1, 1, 1, 1000), (2, 1, 2, 500), (3, 2, 2, 200), (4, 2, 2, 300), (5, 3, 3, 300), (6, 1, 3, 800), (7, 3, 5, 300), (8, 3, 4, 400); CREATE TABLE `item_out` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `location_id` bigint(20) UNSIGNED NOT NULL, `item_id` bigint(20) UNSIGNED NOT NULL, `quantity` int(11) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO `item_out` (`id`, `location_id`, `item_id`, `quantity`) VALUES (1, 1, 2, 20), (2, 1, 1, 25), (3, 2, 2, 25), (4, 3, 3, 25), (5, 3, 5, 10), (6, 3, 4, 15), (7, 1, 1, 200), (8, 2, 2, 50); Using dynamic SQL, I was able to get the individual remaining quantities per item based on their location and item (item_in quantity subtracted by item_out quantity) and have the location names as columns. (see code below): SET #sql = NULL, #sql1 = NULL, #sql2 = NULL; SELECT GROUP_CONCAT( DISTINCT CONCAT('SUM(CASE WHEN `location_id` = ''',`location_id`, ''' THEN quantity END) AS ',`name`)) INTO #sql1 FROM item_in JOIN location on location.id = item_in.location_id; SELECT GROUP_CONCAT( DISTINCT CONCAT('SUM(CASE WHEN `location_id` = ''',`location_id`, ''' THEN quantity END) AS ',`name`)) INTO #sql2 FROM item_out JOIN location on location.id = item_out.location_id; SET #sql = CONCAT('SELECT item.brand AS Item, IFNULL(item_in.Dallas, 0) - IFNULL(item_out.Dallas, 0) AS Dallas, IFNULL(item_in.Boston, 0) - IFNULL(item_out.Boston, 0) AS Boston, IFNULL(item_in.Houston, 0) - IFNULL(item_out.Houston, 0) AS Houston FROM item LEFT JOIN (SELECT item_in.item_id, ', #sql1, ' FROM item_in GROUP BY item_in.item_id) AS item_in ON item.id = item_in.item_id LEFT JOIN (SELECT item_out.item_id, ', #sql2, ' FROM item_out GROUP BY item_out.item_id) AS item_out ON item.id = item_out.item_id'); PREPARE stmt FROM #sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; Result: Item | Dallas | Boston | Houston Nissan Almera M/T 2009-2015 775 0 0 Toyota Corolla A/T 2005-2012 480 425 0 Nissan Terra A/T 2010-2017 800 0 275 Suzuki Esteem M/T 1980-1990 0 0 385 Toyota Fortuner A/T 2014-2020 0 0 290 My question, how do I go about changing the code so that the location name columns is displayed dynamically instead of hardcoding them manually in the query since users can add new locations anytime? if anyone can take a look at my code, i'd really appreciate the help. The only part I'm having trouble is how to not hardcode these lines and do them dynamically: IFNULL(item_in.Dallas, 0) - IFNULL(item_out.Dallas, 0) AS Dallas, IFNULL(item_in.Boston, 0) - IFNULL(item_out.Boston, 0) AS Boston, IFNULL(item_in.Houston, 0) - IFNULL(item_out.Houston, 0) AS Houston
By way of example, consider the following, which uses PHP and the mysqli_ API. (I've used procedural code, but dbo would be more efficient)... <?php /* DROP TABLE IF EXISTS location; CREATE TABLE `location` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (id) ); INSERT INTO `location` (`id`, `name`) VALUES (1, 'Dallas'), (2, 'Boston'), (3, 'Houston'); DROP TABLE IF EXISTS item; CREATE TABLE `item` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `brand` varchar(255) DEFAULT NULL, PRIMARY KEY (id) ); INSERT INTO `item` (`id`, `brand`) VALUES (1, 'Nissan Almera M/T 2009-2015'), (2, 'Toyota Corolla A/T 2005-2012'), (3, 'Nissan Terra A/T 2010-2017'), (4, 'Suzuki Esteem M/T 1980-1990'), (5, 'Toyota Fortuner A/T 2014-2020'); DROP TABLE IF EXISTS item_in; CREATE TABLE `item_in` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `location_id` bigint(20) UNSIGNED NOT NULL, `item_id` bigint(20) UNSIGNED NOT NULL, `quantity` int(11) DEFAULT NULL, PRIMARY KEY (id) ); INSERT INTO `item_in` (`id`, `location_id`, `item_id`, `quantity`) VALUES (1, 1, 1, 1000), (2, 1, 2, 500), (3, 2, 2, 200), (4, 2, 2, 300), (5, 3, 3, 300), (6, 1, 3, 800), (7, 3, 5, 300), (8, 3, 4, 400); DROP TABLE IF EXISTS item_out; CREATE TABLE `item_out` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `location_id` bigint(20) UNSIGNED NOT NULL, `item_id` bigint(20) UNSIGNED NOT NULL, `quantity` int(11) DEFAULT NULL, PRIMARY KEY (id) ); INSERT INTO `item_out` (`id`, `location_id`, `item_id`, `quantity`) VALUES (1, 1, 2, 20), (2, 1, 1, 25), (3, 2, 2, 25), (4, 3, 3, 25), (5, 3, 5, 10), (6, 3, 4, 15), (7, 1, 1, 200), (8, 2, 2, 50); */ require('path/to/connect.ion'); $query = " SELECT l.name city , i.brand item , SUM(x.quantity) total FROM ( SELECT location_id,item_id,'in' type, quantity FROM item_in UNION ALL SELECT location_id,item_id,'out',quantity*-1 FROM item_out ) x JOIN location l ON l.id = x.location_id JOIN item i ON i.id = x.item_id GROUP BY item , city ORDER BY city , item "; $result = mysqli_query($db,$query); $array = array(); while($row = mysqli_fetch_assoc($result)){ $array[] = $row; } foreach($array as $v){ $new_array[$v['city']][$v['item']] = $v['total']; } print_r($new_array); ?> Outputs: Array ( [Boston] => Array ( [Toyota Corolla A/T 2005-2012] => 425 ) [Dallas] => Array ( [Nissan Almera M/T 2009-2015] => 775 [Nissan Terra A/T 2010-2017] => 800 [Toyota Corolla A/T 2005-2012] => 480 ) [Houston] => Array ( [Nissan Terra A/T 2010-2017] => 275 [Suzuki Esteem M/T 1980-1990] => 385 [Toyota Fortuner A/T 2014-2020] => 290 ) ) Or you can swap city and item around in $new_array[$v['city']][$v['item']] = $v['total'];, to get: Array ( [Toyota Corolla A/T 2005-2012] => Array ( [Boston] => 425 [Dallas] => 480 ) [Nissan Almera M/T 2009-2015] => Array ( [Dallas] => 775 ) [Nissan Terra A/T 2010-2017] => Array ( [Dallas] => 800 [Houston] => 275 ) [Suzuki Esteem M/T 1980-1990] => Array ( [Houston] => 385 ) [Toyota Fortuner A/T 2014-2020] => Array ( [Houston] => 290 ) )
How to pull the last data from table 2 using LEFT JOIN with 2 tables?
I'm coding a chat room using 2 mysql tables. One of these tables is the inbox and the other is the messages table. I want to find the table "user_mailboxes" from another table belonging to someone else and sort it by grouping advert_id. I want the last sent message to be at the top and at the specified location. I would be glad if you help. The SQL code I use: SELECT * FROM user_mailboxes LEFT JOIN mbox ON mbox.id = user_mailboxes.message_id WHERE (user_mailboxes.user = '$users['id']' AND user_mailboxes.mailbox = 'Out') || (user_mailboxes.user = '$users['id']' AND user_mailboxes.mailbox = 'In') GROUP BY user_mailboxes.advert_id ORDER BY mbox.created DESC I'm using a Foreach loop. Result: user_mailboxes TABLE mysql CREATE TABLE `mbox` ( `id` int(100) NOT NULL, `message` text COLLATE utf8_unicode_ci, `sentby` int(100) DEFAULT NULL, `sentto` int(100) DEFAULT NULL, `created` datetime DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; INSERT INTO `mbox` (`id`, `message`, `sentby`, `sentto`, `created`) VALUES (1, 'Hello!', 1, 4, '2019-10-25 00:25:38'), (2, 'Last Messages How are you ?', 1, 4, '2019-10-25 00:26:14'), (3, 'Welcome', 1, 2, '2019-10-25 00:26:45'), (4, ':) last messages', 1, 2, '2019-10-25 00:27:02'); mbox TABLE mysql CREATE TABLE `user_mailboxes` ( `id` int(100) NOT NULL, `user` int(100) DEFAULT NULL, `mailbox` enum('Out','In') COLLATE utf8_unicode_ci DEFAULT NULL, `message_id` int(100) DEFAULT NULL, `advert_id` int(100) DEFAULT NULL, `room_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; INSERT INTO `user_mailboxes` (`id`, `user`, `mailbox`, `message_id`, `advert_id`, `room_name`) VALUES (1, 1, 'Out', 1, 67, '67-1'), (2, 4, 'In', 1, 67, '67-1'), (3, 1, 'Out', 2, 67, '67-1'), (4, 4, 'In', 2, 67, '67-1'), (5, 1, 'Out', 3, 1, '1-1'), (6, 2, 'In', 3, 1, '1-1'), (7, 1, 'Out', 4, 1, '1-1'), (8, 2, 'In', 4, 1, '1-1');
showing counter in mysql query
I have mysql query given below. I which counter has been used. if i enter category Id 1 for 3 times then counter is coming 3 which is correct but with this i want if i do not enter then different coloumn should come with NO. output should be KU Electrical Yes 6 2 No 1 2 In this KU and Electrical are my sale channel name. Yes means counter of enteries of KU and No means which have not entered. Please help out in this. i am struggling select SalesChannel.name, Transaction.category_id, count(Transaction.category_id) as "count" from outlets Outlet inner join transactions Transaction on Outlet.id = Transaction.outlet_id inner join sale_channels SalesChannel on SalesChannel.id = Outlet.sale_channel_id group by Transaction.category_id; below are three tables which I used 1) transactions CREATE TABLE IF NOT EXISTS `transactions` ( `id` int(11) NOT NULL, `zone_id` int(11) NOT NULL, `state_id` int(11) NOT NULL, `city_id` int(11) NOT NULL, `category_id` int(11) NOT NULL, `sub_category_id` int(11) NOT NULL, `brand_id` int(11) NOT NULL, `model_id` int(11) NOT NULL, `outlet_id` int(11) NOT NULL, `no_of_units` int(11) NOT NULL, `mop` decimal(10,2) NOT NULL ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1; -- -- Dumping data for table `transactions` -- INSERT INTO `transactions` (`id`, `zone_id`, `state_id`, `city_id`, `category_id`, `sub_category_id`, `brand_id`, `model_id`, `outlet_id`, `no_of_units`, `mop`) VALUES (1, 2, 2, 2, 2, 1, 1, 1, 1, 3, '6.00'), (2, 2, 2, 2, 2, 1, 1, 1, 1, 3, '6.00'), (3, 1, 1, 1, 1, 1, 1, 1, 1, 4, '2.00'), (4, 2, 2, 2, 1, 1, 1, 1, 2, 4, '2.00'); 2) outlets CREATE TABLE IF NOT EXISTS `outlets` ( `id` int(11) NOT NULL, `outlet_code` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `zone_id` int(11) NOT NULL, `state_id` int(11) NOT NULL, `city_id` int(11) NOT NULL, `sale_channel_id` int(11) NOT NULL, `is_active` tinyint(1) NOT NULL, `created` datetime NOT NULL, `modified` datetime NOT NULL ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; -- -- Dumping data for table `outlets` -- INSERT INTO `outlets` (`id`, `outlet_code`, `name`, `zone_id`, `state_id`, `city_id`, `sale_channel_id`, `is_active`, `created`, `modified`) VALUES (1, '1508', 'Ashok electricals', 2, 2, 2, 1, 1, '2016-10-03 00:00:00', '2016-10-03 00:00:00'), (2, '1233', 'vinayak electricals', 1, 1, 1, 2, 1, '2016-10-04 00:00:00', '2016-10-04 00:00:00'); 3) sale_chennals CREATE TABLE IF NOT EXISTS `sale_channels` ( `id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `is_active` tinyint(1) NOT NULL, `created` datetime NOT NULL, `modified` datetime NOT NULL ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; -- -- Dumping data for table `sale_channels` -- INSERT INTO `sale_channels` (`id`, `name`, `is_active`, `created`, `modified`) VALUES (1, 'KU', 1, '2016-10-03 00:00:00', '2016-10-03 00:00:00'), (2, 'Electricals', 1, '2016-10-04 00:00:00', '2016-10-04 00:00:00'); SQL fiddle: http://sqlfiddle.com/#!9/3f497/1
You are grouping by category. That means you get one result row per category. In each of these rows you show the count and a sale channel name. This sale channel name is just one of the names found in the records for the category arbitrarily chosen. I suppose you want to count per category and sale channel. Hence your group by clause should be group by SalesChannel.name, Transaction.category_id: select SalesChannel.name, Transaction.category_id, count(Transaction.category_id) as "count" from outlets Outlet inner join transactions Transaction on Outlet.id = Transaction.outlet_id inner join sale_channels SalesChannel on SalesChannel.id = Outlet.sale_channel_id group by SalesChannel.name, Transaction.category_id; SQL fiddle: http://sqlfiddle.com/#!9/3f497/2 This result, however, doesn't show an entry for Electricals / category 2, because there is no transaction for this combination in the table. If you want to show a zero count for this, you'd have to create the complete result set (i.e. all combinations of channel and category, whether they have a transaction or not) first. Then you'd outer join the transactions: select sc.name, c.id as category_id, count(t.id) as "count" from sale_channels sc cross join categories c left join outlets o on o.sale_channel_id = sc.id left join transactions t on t.outlet_id = o.id and t.category_id = c.id group by sc.name, c.id; SQL fiddle: http://sqlfiddle.com/#!9/60e998/5
MySQL not returning any result from my select query
I have the following multiple fields where I want to show statement of my expense and income. I am making a query to return description, credit, debit and balance from the MySQL query. SQL Fiddle CREATE TABLE IF NOT EXISTS `trans` ( `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `debit` decimal(15,4) NOT NULL, `credit` decimal(15,4) NOT NULL, `catid` smallint(5) NOT NULL, `incomeid` bigint(20) unsigned NOT NULL DEFAULT '0', `expenseid` bigint(20) unsigned NOT NULL DEFAULT '0', `bankid` int(3) unsigned NOT NULL, `date` date NOT NULL, `updated_last` datetime NOT NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ; -- -- Dumping data for table `trans` -- INSERT INTO `trans` (`ID`, `debit`, `credit`, `catid`, `incomeid`, `expenseid`, `bankid`, `date`, `updated_last`) VALUES (1, 0.0000, 2078.1000, 23, 1, 0, 2, '2015-04-01', '2015-04-30 14:16:37'), (2, 0.0000, 2052.8200, 23, 2, 0, 2, '2015-04-02', '2015-04-30 14:17:23'), (3, 0.0000, 4906.6200, 23, 3, 0, 2, '2015-04-02', '2015-04-30 14:17:06'), (4, 0.0000, 12360.0500, 23, 4, 0, 1, '2015-04-02', '2015-04-30 12:18:15'), (5, 0.0000, 10750.0000, 23, 5, 0, 2, '2015-04-03', '2015-04-30 12:25:31'), (6, 0.0000, 2247.2000, 23, 6, 0, 1, '2015-04-03', '2015-04-30 12:29:45'), (7, 0.0000, 4775.3000, 23, 7, 0, 2, '2015-04-04', '2015-04-30 12:37:40'), (8, 0.0000, 2052.8200, 23, 8, 0, 2, '2015-04-04', '2015-04-30 14:16:05'), (9, 2280.9100, 2280.9100, 23, 0, 1, 2, '2015-04-06', '2015-04-30 14:17:51'), (10, 0.0000, 25000.0000, 23, 0, 2, 2, '2015-04-04', '2015-04-30 13:46:03'); CREATE TABLE IF NOT EXISTS `expense` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `type` int(11) unsigned NOT NULL, `date` date NOT NULL, `itemdesc` varchar(255) NOT NULL, `quantity` varchar(30) NOT NULL, `price` decimal(15,4) NOT NULL, `grandtotal` decimal(15,4) NOT NULL, `updated_last` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ; -- -- Dumping data for table `expense` -- INSERT INTO `expense` (`id`, `type`, `date`, `itemdesc`, `quantity`, `price`, `grandtotal`, `updated_last`) VALUES (1, 30, '2015-04-04', 'INT-CITY CASH DEP CHG INC ST-EC 300315', '1', 50.0000, 56.1800, '2015-05-01 02:35:37'), (2, 30, '2015-04-04', 'IMPS P2P 562 508513121760#26-03- 300315', '1', 5.0000, 5.6200, '2015-05-01 02:37:18'), (3, 29, '2015-04-08', 'mobile 1 Bill', '1', 599.0000, 673.0400, '2015-05-01 02:47:01'), (4, 29, '2015-04-08', 'mobile 2 Bill Mar 2015', '1', 627.0000, 704.5000, '2015-05-01 02:58:08'), (5, 38, '2015-04-10', 'staff 1 Salary Mar 2015', '1', 22000.0000, 22000.0000, '2015-05-01 03:02:21'), (6, 38, '2015-04-10', 'staff 2 Salary Mar 2015', '1', 22000.0000, 22000.0000, '2015-05-01 03:03:40'), (7, 29, '2015-04-11', 'landline 2 March 2015', '1', 388.9000, 436.9700, '2015-05-01 04:13:24'), (8, 29, '2015-04-11', 'landline Mar 2015', '1', 605.2300, 680.0400, '2015-05-01 04:20:52'), (9, 29, '2015-04-11', 'pager bill Mar 2015', '1', 591.4000, 664.5000, '2015-05-01 04:23:28'), (10, 29, '2015-04-11', 'phone bill Mar 2015', '1', 198.7500, 223.3200, '2015-05-01 04:26:01'); CREATE TABLE IF NOT EXISTS `items` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `description` varchar(200) NOT NULL, `catid` int(5) unsigned NOT NULL, `status` tinyint(1) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ; -- -- Dumping data for table `items` -- INSERT INTO `items` (`id`, `description`, `catid`, `status`) VALUES (1, 'product 10000', 23, 1), (2, 'product 50000', 23, 1), (3, 'product 100000', 23, 1), (4, 'product 500000', 23, 1), (5, 'product High 10000', 23, 1), (6, 'product High 50000', 23, 1), (7, 'product High 100000', 23, 1), (8, 'product High 500000', 23, 1), (9, 'product Normal 10000', 23, 1), (10, 'product Normal 25000', 23, 1); CREATE TABLE IF NOT EXISTS `income` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `type` smallint(5) unsigned NOT NULL, `date` date NOT NULL, `itemdesc` int(11) unsigned NOT NULL DEFAULT '0', `quantity` varchar(30) NOT NULL, `price` decimal(15,4) NOT NULL, `grandtotal` decimal(15,4) NOT NULL, `updated_last` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ; -- -- Dumping data for table `income` -- INSERT INTO `income` (`id`, `type`, `date`, `itemdesc`, `quantity`, `price`, `grandtotal`, `updated_last`) VALUES (1, 23, '2015-04-01', 18, '10000', 0.1800, 2078.1000, '2015-04-30 14:16:37'), (2, 23, '2015-04-02', 18, '10000', 0.1800, 2052.8200, '2015-04-30 14:17:23'), (3, 23, '2015-04-02', 10, '25000', 0.1700, 4906.6200, '2015-04-30 14:17:06'), (4, 23, '2015-04-02', 12, '100000', 0.1100, 12360.0500, '2015-04-30 12:18:15'), (5, 23, '2015-04-03', 12, '100000', 0.1075, 10750.0000, '2015-04-30 12:25:31'), (6, 23, '2015-04-03', 14, '10000', 0.2000, 2247.2000, '2015-04-30 12:29:45'), (7, 23, '2015-04-04', 10, '25000', 0.1700, 4775.3000, '2015-04-30 12:37:40'), (8, 23, '2015-04-04', 9, '10000', 0.1800, 2052.8200, '2015-04-30 14:16:05'), (9, 23, '2015-04-06', 14, '10000', 0.2000, 2280.9100, '2015-04-30 14:17:51'), (10, 23, '2015-04-04', 53, '250000', 0.1000, 25000.0000, '2015-04-30 13:46:03'); MySQL query: set #depos=0; set #total=0; SELECT A.`date` , A.`debit` , A.`credit` , if( A.`credit` >0, #depos := A.`credit`, #depos := #depos + A.`credit` - A.`debit` ) AS depos_bal, #total := #total + A.`credit` - A.`debit` AS net_bal, C.`itemdesc`, D.`description` FROM `trans` A, `income` B, `expense` C, `items` D WHERE A.`expenseid` = C.`id` AND A.`incomeid` = B.`id` AND B.`itemdesc` = D.`id` AND A.`bankid` = '2' ORDER BY A.`date` ASC, A.`ID` ASC My several queries are just not good enough to get through with it. How do I use the query to get all rows like the following? Date Description Debit Credit Balance 04-04-2015 Item 1 4,775.30 27,445.28 04-04-2015 Item 2 56.18 27,389.10 07-04-2015 Item 3 2,359.56 29,743.04
You have no matching values between your trans, income, and expense tables. So by ANDing "Where A.expenseid = C.id AND A.incomeid = B." will produce no results. If you run these queries you will realize that: select * from trans A inner join income B on A.incomeid = B.id; select * from trans A inner join expense C on A.expenseid = C.id; Instead of ANDing you should left join on your tables: SELECT A.`date` , D.`description`, C.`itemdesc`, A.`debit` , A.`credit`, if( A.`credit` > 0, #depos := A.`credit`, #depos := #depos + A.`credit` - A.`debit` ) AS depos_bal, #total := #total + A.`credit` - A.`debit` AS net_bal FROM `trans` A left join `income` B ON A.`incomeid` = B.`id` left join `expense` C on A.`expenseid` = C.`id` left join `items` D ON B.`itemdesc` = D.`id` WHERE A.`bankid` = '2' ORDER BY A.`date` ASC, A.`ID` ASc;
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;