Mysql : Pivot table According to status - mysql

My DB structure and details below
CREATE TABLE `tbldakmst` (
`inwardId` int(11) NOT NULL,
`dakType` int(3) DEFAULT NULL,
`dakMarkTo` int(4) DEFAULT NULL,
`letterNo` varchar(100) DEFAULT NULL,
`markDeptt` varchar(20) DEFAULT NULL,
`dakSenderName` varchar(256) DEFAULT NULL,
`subject` varchar(256) DEFAULT NULL,
`remarks` text,
`comments` text,
`handoverDate` datetime DEFAULT NULL,
`handoverTo` int(11) DEFAULT NULL,
`forwardedTo` int(11) DEFAULT NULL,
`forwardedOn` datetime DEFAULT NULL,
`forwardedFrom` int(11) DEFAULT NULL,
`status` enum('0','1','2','3','4','5') DEFAULT NULL COMMENT '0=>CREATED, 1=>MARK TO, 2 => FORWARD TO, 3=>INITIATED, 4=>INITIATED AND DISPOSED, 5=>DISPOSED',
`createdBy` int(11) DEFAULT NULL,
`createdOn` datetime DEFAULT CURRENT_TIMESTAMP,
`modifiedBy` int(11) DEFAULT NULL,
`modifiedOn` datetime DEFAULT NULL,
`fileInitiateBy` int(11) DEFAULT NULL,
`fileInitiatedOn` datetime DEFAULT NULL,
`disposedBy` int(11) DEFAULT NULL,
`disposedOn` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `tbldakmst` (`inwardId`, `dakType`, `dakMarkTo`, `letterNo`, `markDeptt`, `dakSenderName`, `subject`, `remarks`, `comments`, `handoverDate`, `handoverTo`, `forwardedTo`, `forwardedOn`, `forwardedFrom`, `status`, `createdBy`, `createdOn`, `modifiedBy`, `modifiedOn`, `fileInitiateBy`, `fileInitiatedOn`, `disposedBy`, `disposedOn`) VALUES
(1, 0, 3, 'letter 5634', 'Office Dak', 'dheeraj kumar nayak', 'My subject data is here', 'Remrks Datammm VBCBCBBBBB', 'disposed again', '1970-01-26 00:00:00', 3, 3, '2017-05-02 15:14:50', 2, '5', 2, '2017-05-01 17:40:32', 3, '2017-05-07 15:42:40', 3, '2017-05-07 14:07:35', 3, '2017-05-07 14:39:51'),
(2, 0, 4, 'letter no 787887', 'Office Dak', 'kAMLESH kUMAR', 'subj', 'Remarks data', 'MY COMMENTS', '2017-05-02 15:14:50', 4, 2, '2017-05-02 15:14:50', 2, '2', 0, '2017-05-02 11:13:00', 2, '2017-05-05 13:00:44', NULL, NULL, 2, NULL),
(3, 0, 2, 'letter 5634', 'Office Dak', 'dheeraj kumar nayak', 'Need operator credentiasl', 'file putted edited', 'gdfgfg', '1970-01-01 00:00:00', 2, 3, NULL, 2, '1', 2, '2017-05-03 11:03:49', 2, '2017-05-04 14:48:48', NULL, NULL, NULL, NULL),
(4, 0, 2, 'letter 567', 'Office Dak', 'Dheraj Kumar', 'operator activation request from CSC-SPV', 'Personal Visit by EA', 'Disposed Now', '2017-05-07 00:00:00', 2, 2, NULL, 3, '5', 3, '2017-05-07 15:46:06', 2, '2017-05-07 16:10:14', 2, '2017-05-07 16:09:17', 2, '2017-05-07 16:10:14'),
(5, 0, 3, 'letter no 5566rr', 'Office Dak', 'ranjeet vaghle', 'operator request', 'proceed', 'File issues resolved and file is diposed', '0000-00-00 00:00:00', 3, 2, NULL, 3, '4', 3, '2017-05-07 15:55:32', 2, '2017-05-07 16:06:58', 2, '2017-05-07 16:06:58', 2, '2017-05-07 16:06:58'),
(6, 0, 2, 'letter 5634', 'Office Dak', 'dheeraj kumar nayak', 'hjjh', 'hjkhj', NULL, '0000-00-00 00:00:00', 2, NULL, NULL, NULL, '1', 2, '2017-05-07 17:27:36', NULL, NULL, NULL, NULL, NULL, NULL),
(7, 0, 2, 'Letter Number -56788899', 'Office Dak', 'dheeraj kumar nayak', 'dsfs', 'fdsfdsf', 'initiated', '0000-00-00 00:00:00', 2, 2, NULL, 2, '3', 2, '2017-05-07 17:51:56', 2, '2017-05-07 17:52:54', 2, '2017-05-07 17:52:54', NULL, NULL);
ALTER TABLE `tbldakmst`
ADD PRIMARY KEY (`inwardId`);
ALTER TABLE `tbldakmst` MODIFY `inwardId` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8;
I have tried:
SELECT
sum(CASE
WHEN status = '1' THEN 1
ELSE 0
END) AS 'pending',
sum(CASE
WHEN status = '3' THEN 1
ELSE 0
END) AS 'initiated',
sum(CASE
WHEN status = '4' OR status = '5' THEN 1
ELSE 0
END) AS 'disposed' FROM tbldakmst
Above Query Output Was :
pending initiated disposed
2 1 3
<!-- Note:Status(0,1) ==>Pending ,Status (3) ==>Initiated,Status(4,5)==>Disposed
column FileInitiatedBy => User Value which one has initiated file.
Column disposedBy=> User Value which one has disposed file.
Column dakmarkTo => User Value which one have pending file -->
But I want Result Like this
User | Pending | Initiated | Disposed |
------------------------------------------------------
User 2 | 1 | 1 | 2 |
------------------------------------------------------
User 3 | 2 | 3 | 4 |
------------------------------------------------------

SELECT u.name AS 'Name',
sum(CASE
WHEN tb.status in ('0','1') AND (u.id = tb.dakMarkTo OR u.id = tb.createdBy) THEN 1
ELSE 0
END) AS 'pending' ,
sum(CASE
WHEN tb.status in ('3') AND u.id = tb.fileInitiateBy THEN 1
ELSE 0
END) AS 'initiated',
sum(CASE
WHEN tb.status in ('4', '5') AND u.id = tb.disposedBy THEN 1
ELSE 0
END) AS 'disposed'
FROM
tbldakmst tb, user u
group by u.name

Related

Complex JOIN SQL query in Laravel 5

I have three tables that I need to join: products, orders_items, orders
The products table contains, obviously, the products. When a user adds a product to their cart, it creates an order and a line item in the order_items table. When the user pays, it puts the total paid into the orders table. Therefore, purchased products removed from inventory only include products that are attached to an order_item attached to an order that has been marked paid.
I need to return all the products, but also somehow calculate how many are left in inventory. The products table contains a field called "initial_quantity" which is how many of the product we started with. If that field is NULL, there's no limit on the product.
Here is my current query, which works just fine for returning all the products of a certain type:
$swims = Product::where('product_type_id', 1)
->whereDate('visible_date', '<=', Carbon::now())
->where('active', true)
->where(function ($query) {
$query->where('end_date', '>=', Carbon::now())
->orWhere('end_date', null);
})
->get();
Here is the SQL for that query:
select * from `products` where `product_type_id` = 1 and date(`visible_date`) <= '2019-08-08 17:10:12' and `active` = 1 and (`end_date` >= '2019-08-08 17:10:12' or `end_date` is null)
The above query returns three results:
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+
| id | name | base_price | end_date | visible_date | initial_quantity | product_type_id | active |
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+
| 1 | membership | 30.97 | NULL | 2019-08-04 | NULL | 1 | 1 |
| 12 | repellendus | 779.24 | 2027-03-16 | 1990-12-19 | NULL | 1 | 1 |
| 16 | ducimus | 708.33 | NULL | 1999-03-24 | NULL | 1 | 1 |
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+
I can run another query to see how much of each product has been sold:
select product_id, SUM(quantity) sold from `order_items` inner join `orders` on `order_items`.`order_id` = `orders`.`id` and `orders`.`paid` is not null group by `product_id`
This query returns:
+------------+------+
| product_id | sold |
+------------+------+
| 1 | 5 |
| 7 | 3 |
| 11 | 1 |
| 12 | 1 |
+------------+------+
What I'm looking for is a way to combine those two (or similar) queries so I get all the products I'm looking for, plus the quantity of those products that have been sold, to give me a result similar to this:
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+------+
| id | name | base_price | end_date | visible_date | initial_quantity | product_type_id | active | sold |
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+------+
| 1 | membership | 30.97 | NULL | 2019-08-04 | NULL | 1 | 1 | 5 |
| 12 | repellendus | 779.24 | 2027-03-16 | 1990-12-19 | NULL | 1 | 1 | 1 |
| 16 | ducimus | 708.33 | NULL | 1999-03-24 | NULL | 1 | 1 | 0 |
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+------+
I would like a query that returns all products I'm searching for and also how many are remaining. I've tried join, leftJoin, rightJoin, subquery joins and unions. Laravel doesn't seem to have outer joins or I would have tried those too.
I have tried this query and many other iterations and I always get a syntax error:
select * from (`products` where `product_type_id` = 1 and date(`visible_date`) <= '2019-08-08 17:10:12' and `active` = 1 and (`end_date` >= '2019-08-08 17:10:12' or `end_date` is null)) x INNER JOIN (select product_id, SUM(quantity) sold from `order_items` inner join `orders` on `order_items`.`order_id` = `orders`.`id` and `orders`.`paid` is not null group by `product_id`) y ON x.id = y.product_id
Can anybody come up with the query I'm looking for? If not in Laravel then in raw SQL would be fine and I can use it as-is or try to Laravelize it.
Thank you in advance.
Here is my MRE:
CREATE TABLE `products` (
`id` bigint(20) UNSIGNED NOT NULL,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`base_price` double(5,2) NOT NULL,
`end_date` date DEFAULT NULL,
`visible_date` date DEFAULT NULL,
`initial_quantity` smallint(5) UNSIGNED DEFAULT NULL,
`product_type_id` int(10) UNSIGNED NOT NULL,
`active` tinyint(3) UNSIGNED NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `products` (`id`, `name`, `base_price`, `end_date`, `visible_date`, `initial_quantity`, `product_type_id`, `active`) VALUES
(1, 'membership', 30.97, NULL, '2019-08-04', NULL, 1, 1),
(2, 'delectus', 347.44, NULL, '1975-06-08', 45, 1, 0),
(3, 'aut', 283.36, '1981-05-30', '1973-08-18', NULL, 3, 0),
(4, 'adipisci', 984.00, '1986-01-04', '1989-03-29', NULL, 3, 0),
(5, 'voluptas', 310.55, '2012-05-04', '1992-11-16', 45, 2, 1),
(6, 'quia', 657.81, '1976-11-23', '1978-10-23', 57, 2, 0),
(7, 'delectus', 601.91, NULL, '1987-03-09', 53, 2, 1),
(8, 'consequatur', 723.25, '1994-09-24', '1985-01-23', 33, 1, 0),
(9, 'perferendis', 427.33, NULL, '1995-12-08', 51, 3, 1),
(10, 'id', 674.39, '1974-12-13', '2007-05-12', 41, 2, 0),
(11, 'maxime', 133.49, NULL, '1986-07-15', NULL, 2, 1),
(12, 'repellendus', 779.24, '2027-03-16', '1990-12-19', NULL, 1, 1),
(13, 'sit', 956.76, NULL, '1993-07-02', 39, 2, 0),
(14, 'molestiae', 425.16, NULL, '1981-03-25', NULL, 3, 1),
(15, 'omnis', 418.78, '1976-11-03', '2007-10-07', NULL, 3, 1),
(16, 'ducimus', 708.33, NULL, '1999-03-24', NULL, 1, 1),
(17, 'numquam', 328.26, '2011-09-19', '2001-10-07', NULL, 3, 1),
(18, 'est', 962.26, NULL, '1970-12-24', NULL, 1, 0),
(19, 'quis', 520.18, NULL, '1978-03-25', NULL, 3, 0),
(20, 'facere', 891.89, NULL, '1979-10-31', 36, 3, 0),
(21, 'voluptatem', 518.47, '1982-06-26', '1975-03-14', NULL, 1, 1);
COMMIT;
CREATE TABLE `order_items` (
`order_id` bigint(20) UNSIGNED NOT NULL,
`product_id` bigint(20) UNSIGNED NOT NULL,
`quantity` tinyint(3) UNSIGNED NOT NULL DEFAULT '1',
`price` double(5,2) NOT NULL,
`tax` double(5,2) NOT NULL,
`buy_now` tinyint(3) UNSIGNED NOT NULL DEFAULT '1',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `order_items` (`order_id`, `product_id`, `quantity`, `price`, `tax`, `buy_now`, `created_at`, `updated_at`) VALUES
(1, 1, 1, 30.97, 4.03, 1, '2019-08-04 11:35:26', '2019-08-04 11:35:26'),
(1, 12, 1, 779.24, 654.56, 1, '2019-08-04 11:35:26', '2019-08-04 11:35:26'),
(2, 1, 1, 30.97, 4.03, 1, '2019-08-04 11:56:16', '2019-08-04 11:56:16'),
(3, 1, 1, 30.97, 4.03, 1, '2019-08-07 17:25:43', '2019-08-07 17:25:43'),
(3, 7, 1, 601.91, 210.67, 1, '2019-08-07 17:25:43', '2019-08-07 17:25:43'),
(4, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:44:45', '2019-08-08 15:44:45'),
(4, 7, 1, 601.91, 210.67, 1, '2019-08-08 15:44:45', '2019-08-08 15:44:45'),
(5, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:46:07', '2019-08-08 15:46:07'),
(5, 11, 1, 133.49, 88.10, 1, '2019-08-08 15:46:07', '2019-08-08 15:46:07'),
(6, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:46:55', '2019-08-08 15:46:55'),
(6, 16, 1, 708.33, 687.08, 1, '2019-08-08 15:46:55', '2019-08-08 15:46:55'),
(7, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:47:37', '2019-08-08 15:47:37'),
(7, 7, 1, 601.91, 210.67, 1, '2019-08-08 15:47:37', '2019-08-08 15:47:37'),
(8, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:48:13', '2019-08-08 15:48:13'),
(8, 11, 1, 133.49, 88.10, 1, '2019-08-08 15:48:13', '2019-08-08 15:48:13');
CREATE TABLE `orders` (
`id` bigint(20) UNSIGNED NOT NULL,
`user_id` bigint(20) UNSIGNED NOT NULL,
`subtotal` double(7,2) DEFAULT NULL,
`tax` double(7,2) DEFAULT NULL,
`paid` double(7,2) DEFAULT NULL,
`transaction` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `orders` (`id`, `user_id`, `subtotal`, `tax`, `paid`, `transaction`, `created_at`, `updated_at`) VALUES
(1, 1, 810.21, 658.59, 12343.00, NULL, '2019-08-04 11:35:26', '2019-08-04 11:35:26'),
(2, 1, 30.97, 4.03, NULL, NULL, '2019-08-04 11:56:16', '2019-08-04 11:56:16'),
(3, 1, 632.88, 214.70, 847.58, NULL, '2019-08-05 17:25:43', '2019-08-07 17:25:43'),
(4, 5, 632.88, 214.70, 847.58, NULL, '2019-08-08 15:44:45', '2019-08-08 15:44:45'),
(5, 5, 164.46, 92.13, 256.59, NULL, '2019-08-08 15:46:07', '2019-08-08 15:46:07'),
(6, 5, 739.30, 691.11, NULL, NULL, '2019-08-08 15:46:55', '2019-08-08 15:46:55'),
(7, 10, 632.88, 214.70, 847.58, NULL, '2019-08-08 15:47:37', '2019-08-08 15:47:37'),
(8, 10, 164.46, 92.13, NULL, NULL, '2019-08-08 15:48:13', '2019-08-08 15:48:13');
SELECT a.*
, COALESCE(b.sold,0) sold
FROM
( SELECT *
FROM products p
WHERE p.product_type_id = 1
AND DATE(p.visible_date) <= '2019-08-08 17:10:12'
AND p.active = 1
AND (p.end_date >= '2019-08-08 17:10:12' or p.end_date IS NULL)
) a
LEFT
JOIN
( SELECT product_id
, SUM(quantity) sold
FROM order_items oi
JOIN orders o
ON o.id = oi.order_id
AND o.paid is not null
GROUP
BY product_id
) b
ON b.product_id = a.id;
...or, better...
SELECT p.*
, COALESCE(y.sold,0) sold
FROM products p
LEFT
JOIN
( SELECT product_id
, SUM(quantity) sold
FROM order_items oi
JOIN orders o
ON o.id = oi.order_id
AND o.paid is not null
GROUP
BY product_id
) y
ON y.product_id = p.id
WHERE p.product_type_id = 1
AND DATE(p.visible_date) <= '2019-08-08 17:10:12'
AND p.active = 1
AND (p.end_date >= '2019-08-08 17:10:12' OR p.end_date IS NULL)

MySql. 'group by' by parts

there is a table
CREATE TABLE geography_schedule (
id int(10) UNSIGNED NOT NULL,
geography_address_id int(10) UNSIGNED NOT NULL,
geography_city_id int(10) UNSIGNED NOT NULL,
sort int(5) UNSIGNED NOT NULL DEFAULT '500',
site varchar(5) NOT NULL DEFAULT 'site',
group_id int(10) NOT NULL DEFAULT '0',
day int(10) NOT NULL DEFAULT '1',
all_day tinyint(2) NOT NULL DEFAULT '0',
freeday int(10) NOT NULL DEFAULT '0',
from varchar(5) NOT NULL DEFAULT '09:00',
to varchar(5) NOT NULL DEFAULT '18:00',
timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
timestamp_update timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO geography_schedule (from, to, geography_address_id, day_from, day_to, group_id) VALUES
('09:00', '18:00', 533, 1, 1, 1),
('09:00', '18:00', 533, 2, 2, 1),
('11:00', '17:00', 533, 3, 3, 1),
('11:00', '17:00', 533, 4, 4, 1),
('09:00', '18:00', 533, 5, 5, 1),
('10:00', '17:00', 533, 6, 6, 1),
('09:00', '18:00', 533, 7, 7, 1);
I have a mysql query from this table enter image description here
SELECT `from`,`to`, `geography_address_id`, MIN(`day`) as `day_from`
,MAX(`day`) as `day_to`,`group_id`
FROM `geography_schedule`
WHERE `geography_address_id` = 533
GROUP BY `from`,`to`
ORDER BY `geography_schedule`.`day` ASC
result:
I need to group by lines 9:00 - 18:00 to save days day_from & day_to in proper order.
Is it possible to use GROUP BY in such a way it will give the result like this?

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 rows in to columns (but dynamic rows)

This is my SQL table and data. http://sqlfiddle.com/#!9/effe2
CREATE TABLE IF NOT EXISTS `CustomValue` (
`id` int(11) NOT NULL,
`customFieldId` int(11) NOT NULL,
`relatedId` int(11) NOT NULL,
`fieldValue` text COLLATE utf8_unicode_ci,
`createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `CustomValue` (`id`, `customFieldId`, `relatedId`, `fieldValue`, `createdAt`) VALUES
(1, 10, 4031, NULL, '2015-11-05 04:25:00'),
(2, 14, 4031, 'adsas#das.sadsa', '2015-11-05 04:25:00'),
(3, 13, 4031, '456', '2015-11-05 04:25:00'),
(4, 16, 4031, '2015-11-09', '2015-11-05 04:25:00'),
(5, 9, 4031, '456', '2015-11-05 04:25:00'),
(6, 11, 4031, 'dsasda', '2015-11-05 04:25:00'),
(7, 15, 4031, '1', '2015-11-05 04:25:00');
Right now it is as,
id customFieldId relatedId fieldValue createdAt
1 10 4031 (null) November, 05 2015 04:25:00
2 14 4031 adsas#das.sadsa November, 05 2015 04:25:00
3 13 4031 456 November, 05 2015 04:25:00
4 16 4031 2015-11-09 November, 05 2015 04:25:00
5 9 4031 456 November, 05 2015 04:25:00
6 11 4031 dsasda November, 05 2015 04:25:00
7 15 4031 1 November, 05 2015 04:25:00
I need to group by relatedId and and get the final output as 1 row for each relatedId.
This is the reference table.
CREATE TABLE IF NOT EXISTS `CustomField` (
`id` int(11) NOT NULL,
`customTypeId` int(11) NOT NULL,
`fieldName` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`relatedTable` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`defaultValue` text COLLATE utf8_unicode_ci,
`sortOrder` int(11) NOT NULL DEFAULT '0',
`enabled` char(1) COLLATE utf8_unicode_ci DEFAULT '1',
`listItemTag` char(1) COLLATE utf8_unicode_ci DEFAULT NULL,
`required` char(1) COLLATE utf8_unicode_ci DEFAULT '0',
`onCreate` char(1) COLLATE utf8_unicode_ci DEFAULT '1',
`onEdit` char(1) COLLATE utf8_unicode_ci DEFAULT '1',
`onView` char(1) COLLATE utf8_unicode_ci DEFAULT '1',
`listValues` text COLLATE utf8_unicode_ci,
`label` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`htmlOptions` text COLLATE utf8_unicode_ci
) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `CustomField` (`id`, `customTypeId`, `fieldName`, `relatedTable`, `defaultValue`, `sortOrder`, `enabled`, `listItemTag`, `required`, `onCreate`, `onEdit`, `onView`, `listValues`, `label`, `htmlOptions`) VALUES
(13, 1, 'HOMEEMAIL', 'people', '', 0, '1', NULL, '1', '1', '1', '1', NULL, 'Home Email', ''),
(9, 1, 'LANDPHONENO', 'people', '', 0, '1', NULL, '1', '1', '1', '1', NULL, 'Land Phone No', ''),
(10, 12, 'ABOUTME', 'people', '', 0, '1', NULL, '0', '1', '1', '1', NULL, 'About Me', ''),
(11, 3, 'PHONENUMBER2', 'people', '', 0, '1', NULL, '1', '1', '1', '1', NULL, 'Phone Number 2', ''),
(14, 3, 'ALTERNATEEMAIL', 'people', '', 0, '1', NULL, '1', '1', '1', '1', NULL, 'Alternate Email', ''),
(15, 11, 'SCHOOLING?', 'people', '', 0, '1', NULL, '1', '1', '1', '1', NULL, 'Schooling?', ''),
(16, 4, 'JOINDATE', 'people', '', 0, '1', NULL, '1', '1', '1', '1', NULL, 'Join Date', '');
The final output should be,
relatedId | Alternate Email | Home Email | Join Date | Land Phone No | Phone Number 2 | Schooling?
--------------------------------------------------------------------------------------------------
4031 | adsas#das.sadsa | 456 | 2015-11-09| 456 | dsasda | 1
relatedId | Alternate Email | Home Email | Join Date | Land Phone No | Phone Number 2 | Schooling? | Interest
--------------------------------------------------------------------------------------------------
4033 | adsas#das.sadsa | 456 | 2015-11-09| 456 | dsasda | 1 | Drawing
The output of phpmyadmin
What you need here is PIVOT rows into columns, MySQL however doesn't have a native pivot operator like SQL Server or Oracle for example. But you can use CASE expression with group by to do this like this:
SELECT
v.relatedId, v.CreatedAt,
MAX(IF(f.fieldName = 'ABOUTME', COALESCE(v.fieldValue, f.defaultValue) , NULL)) AS 'ABOUTME',
MAX(IF(f.fieldName = 'ALTERNATEEMAIL', COALESCE(v.fieldValue, f.defaultValue) , NULL)) AS 'ALTERNATEEMAIL',
MAX(IF(f.fieldName = 'HOMEEMAIL', COALESCE(v.fieldValue, f.defaultValue) , NULL)) AS 'HOMEEMAIL',
MAX(IF(f.fieldName = 'JOINDATE', COALESCE(v.fieldValue, f.defaultValue) , NULL)) AS 'JOINDATE',
MAX(IF(f.fieldName = 'LANDPHONENO', COALESCE(v.fieldValue, f.defaultValue) , NULL)) AS 'LANDPHONENO',
MAX(IF(f.fieldName = 'PHONENUMBER2', COALESCE(v.fieldValue, f.defaultValue) , NULL)) AS 'PHONENUMBER2',
MAX(IF(f.fieldName = 'SCHOOLING?', COALESCE(v.fieldValue, f.defaultValue) , NULL)) AS 'SCHOOLING?'
FROM customField AS f
INNER JOIN Customvalue AS v ON f.Id = v.customFieldId
GROUP BY v.relatedId, v.CreatedAt;
And to do it dynamically you have to do it with dynamic sql like this:
SET #Colvalues = NULL;
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(f.fieldName = ''',
f.fieldName, ''', COALESCE(v.fieldValue, f.defaultValue) , NULL)) AS ', '''', f.fieldName , '''')
) INTO #Colvalues
FROM customField AS f
INNER JOIN Customvalue AS v ON f.Id = v.customFieldId;
SET #sql = CONCAT('SELECT
v.relatedId, v.CreatedAt, ', #Colvalues , '
FROM customField AS f
INNER JOIN Customvalue AS v ON f.Id = v.customFieldId
GROUP BY v.relatedId, v.CreatedAt;');
PREPARE stmt
FROM #sql;
EXECUTE stmt;
Note that:
If the field value is null it will set the value from the default value field, thats what COALESCE(v.fieldValue, f.defaultValue) do.
You can eliminate NULL values like in the field Aboutname case, by adding a WHERE v.fieldValue IS NOT NULL.
This will give you:

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;