MySQL get all parents - mysql

We have orders and RMA's. RMA's can be created with order_products of an order. If in the RMA a new product is send, the product can also be added to a new RMA, and so on.
Now for example, I have this schematic structure of an order with RMA orders.
Order (1)
|-> RMA (2)
|-> RMA (3)
|-> RMA (4)
|-> RMA (5)
Now I want to traverse up from RMA (5), all the way up. So actually I want to get 5 records from the database containing all the RMA's and the original order (All from the order table). How can I do this, given the database structure shown below.
Here is a SQLFiddle.
CREATE TABLE `order` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`type` varchar(5) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
CREATE TABLE `order_product` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`order_id` int(11) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE `order_rma_product` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`order_id` int(11) DEFAULT NULL,
`order_product_id` int(11) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
INSERT INTO `order` (`id`, `type`, `description`)
VALUES
(1, 'order', 'Original order'),
(2, 'rma', 'RMA of order 1'),
(3, 'rma', 'RMA of order 2'),
(4, 'rma', 'RMA of order 3'),
(5, 'rma', 'RMA of order 4');
INSERT INTO `order_product` (`id`, `order_id`, `description`)
VALUES
(1, 1, 'Product'),
(2, 2, 'Product'),
(3, 3, 'Product'),
(4, 4, 'Product');
INSERT INTO `order_rma_product` (`id`, `order_id`, `order_product_id`, `description`)
VALUES
(1, 2, 1, 'Return product'),
(2, 3, 2, 'Return product'),
(3, 4, 3, 'Return product'),
(4, 5, 4, 'Return product');
I have tried this, but this give's me one row, so i tried contact_ws to get them all in on column. But this only works for the given set of JOINS, so not unlimited going up.
SELECT CONCAT_WS(',', op.order_id, op1.order_id, op2.order_id)
FROM `order` o
JOIN order_rma_product orp ON o.id = orp.order_id
JOIN order_product op ON orp.order_product_id = op.id
JOIN order_rma_product orp1 ON op.order_id = orp1.order_id
JOIN order_product op1 ON orp1.order_product_id = op1.id
JOIN order_rma_product orp2 ON op1.order_id = orp2.order_id
JOIN order_product op2 ON orp2.order_product_id = op2.id
WHERE o.id = '5';

Related

Query Data from multiple sql tables

I have an ERD above. I want to get the price of the room based on channel and also the status (isInvisible) of the hotel that owns the room mentioned.
Also a RESTful-API endpoint for that, I tried many times on this assignment and can't get it right as I use Nodejs to write an API GET /api/${roomId}/price but the query doesn't work:
SELECT RoomPrice.price, Status.isInvisible
FROM RoomPrice
INNER JOIN Status
ON (RoomPrice.RoomID = Room.Id AND RoomPrice.ChannelID = ChannelId)
AND (Status.HotelID = Hotels.ID AND Status.ChannelID = ChannelID)
I use query below to create my database in WorkBench:
DROP TABLE IF EXISTS `address`;
CREATE TABLE `address` (
`id` int(9) unsigned NOT NULL AUTO_INCREMENT,
`hotel_id` int(9) unsigned NOT NULL,
`address` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY(hotel_id) REFERENCES hotels(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `address` (`hotel_id`, `address`)
VALUES
(1, '7008 Lynch Centers Apt. 596\nLysannemouth, RI 43355'),
(2, '04795 Stanley Mount Apt. 114\nDorrisborough, DC 38070-3542'),
(1, '24586 Eliseo Haven Suite 045\nKossville, WY 17890-7936'),
(2, '639 Toy Corners\nBashirianfort, CA 08964-7258');
DROP TABLE IF EXISTS `channels`;
CREATE TABLE `channels` (
`id` int(9) unsigned NOT NULL AUTO_INCREMENT,
`url` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `channels` (`id`, `url`, `name`)
VALUES
(1, 'http://www.beahan.com/', 'quod'),
(2, 'http://www.douglas.com/', 'sit');
DROP TABLE IF EXISTS `hotels`;
CREATE TABLE `hotels` (
`id` int(9) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `hotels` (`id`, `name`)
VALUES
(1, 'illum'),
(2, 'aliquid');
DROP TABLE IF EXISTS `rooms`;
CREATE TABLE `rooms` (
`id` int(9) unsigned NOT NULL AUTO_INCREMENT,
`hotel_id` int(9) unsigned NOT NULL,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY(hotel_id) REFERENCES hotels(id)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
INSERT INTO `rooms` (`id`, `hotel_id`, `name`)
VALUES
(1, 1, 'vel'),
(2, 2, 'fugit'),
(3, 1, 'doloribus'),
(4, 2, 'ut'),
(5, 1, 'et');
DROP TABLE IF EXISTS `room_prices`;
CREATE TABLE `room_prices` (
`room_id` int(9) unsigned NOT NULL,
`channel_id` int(9) unsigned NOT NULL,
`price` decimal(10,2) NOT NULL,
PRIMARY KEY (room_id, channel_id),
FOREIGN KEY(room_id) REFERENCES rooms(id),
FOREIGN KEY(channel_id) REFERENCES channels(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `room_prices` (`room_id`, `channel_id`, `price`)
VALUES
(1, 1, '50687.86'),
(1, 2, '6687.86'),
(2, 1, '10687.86'),
(2, 2, '274739.20'),
(3, 1, '3828.63'),
(3, 2, '12525.86'),
(4, 1, '2623587.86'),
(4, 2, '125151.00'),
(5, 1, '2358704.85'),
(5, 2, '7347473.86');
DROP TABLE IF EXISTS `status`;
CREATE TABLE `status` (
`hotel_id` int(9) unsigned NOT NULL,
`channel_id` int(9) unsigned NOT NULL,
`isInvisible` BOOLEAN NOT NULL,
PRIMARY KEY (hotel_id, channel_id),
FOREIGN KEY(hotel_id) REFERENCES hotels(id),
FOREIGN KEY(channel_id) REFERENCES channels(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `status` (`hotel_id`, `channel_id`, `isInvisible`)
VALUES
(1, 1, false),
(2, 1, true),
(1, 2, true),
(2, 2, true);
I want that once I query to search for the price of roomId (i.e 1) it returns 2 rows (as the mock data only have 2 rows in channels table) that show:
room_id channel_id price isInvisible
1 1 xxxx.xx 0
1 2 xxxx.xx 1
At this moment, I use the query as DRapp help
SELECT
rp.room_id,
rp.channel_id,
rp.price,
s.isInvisible
FROM
room_prices rp
JOIN status s
ON (rp.channel_id = s.channel_id)
JOIN rooms r
ON (rp.room_id = r.id)
JOIN hotels h
ON (r.hotel_id = h.id)
WHERE rp.room_id = 1
It returns 4 rows (instead of 2 rows as expected)
room_id channel_id price isInvisible
1 1 xxxx.xx 0
1 2 xxxx.xx 1
1 1 xxxx.xx 1
1 2 xxxx.xx 1
You need to identify each of the relations as your ERD shows. Each table is joined to its respective context. Dont jump/skip. The only time you can in this scenario is to skip through the channels since the RoomPrice and Status table EACH have a "ChannelId" to qualify the join
SELECT
rp.price,
s.isInvisible
FROM
Room_Prices rp
JOIN Rooms r
on rp.room_id = r.id
JOIN Status s
ON rp.Channel_ID = s.Channel_Id
AND r.hotel_id = s.hotel_id
WHERE
rp.room_id = 1
I had to revise the query. I looked deeper and noticed your CHANNEL table ALSO had the Hotel, so I had to go from the room prices to the room table. From the room table, I can get the hotel. Now that I have the channel from room prices, AND the hotel ID from the rooms table. So NOW I join to the status table on BOTH columns getting the expected single row per room you are expecting.

SQL sorted by a diferent fields

I have the next tables and rows. And I need to write a SELECT that returns all categories sorted by:
(A) the number of items they have
and (B) the category name.
This query should fetch the following columns: the category name, the number of items (AS N_ITEMS) and the average price of the titles in that category (AS AVERAGE_PRICE)
CREATE TABLE `category` (
`CATEGORY_ID` int(11) NOT NULL,
`CATEGORY_NAME` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `category` (`CATEGORY_ID`, `CATEGORY_NAME`) VALUES
(1, 'Sports'),
(2, 'Actualités'),
(3, 'Animaux'),
(4, 'Economie'),
(5, 'Cuisine');
CREATE TABLE `item` (
`ITEM_ID` int(11) NOT NULL,
`CATEGORY_ID` int(11) NOT NULL,
`ITEM_NAME` varchar(50) NOT NULL,
`ITEM_PRICE` decimal(8,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `item` (`ITEM_ID`, `CATEGORY_ID`, `ITEM_NAME`, `ITEM_PRICE`) VALUES
(1, 1, 'Equip', '6.00'),
(2, 2, 'Le Monde', '3.00'),
(3, 2, 'Le Parisien', '2.50'),
(4, 2, 'France soir', '3.00'),
(5, 3, '30 Million damis', '6.20'),
(6, 3, 'Cheval pratique', '4.50'),
(7, 4, 'Capital', '2.50');
ALTER TABLE `category`
ADD PRIMARY KEY (`CATEGORY_ID`);
ALTER TABLE `item`
ADD PRIMARY KEY (`ITEM_ID`);
ALTER TABLE `category`
MODIFY `CATEGORY_ID` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `item`
MODIFY `ITEM_ID` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;
You can try below -
select CATEGORY_NAME, count(ITEM_ID) as noofItem,avg(item_price) as avgprice
from category inner join item on category.category_id=item.category_id
group by CATEGORY_NAME
order by noofItem,CATEGORY_NAME

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 return rows from last day only for a specific ID

I have 2 tables: 'clients' and 'orders', joined on the field 'client_id'.
CREATE TABLE IF NOT EXISTS `clients` (
`client_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(120) NOT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
INSERT INTO `clients` (`client_id`, `name`) VALUES
(1, 'Ted Bundy'),
(2, 'Terry Towl');
CREATE TABLE IF NOT EXISTS `orders` (
`order_id` int(11) NOT NULL AUTO_INCREMENT,
`client_id` int(11) NOT NULL,
`description` varchar(70) NOT NULL,
`order_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`order_id`),
KEY `client_id` (`client_id`),
KEY `created` (`order_date`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
INSERT INTO `orders` (`order_id`, `client_id`, `description`, `order_date`) VALUES
(1, 1, 'Shirt', '2015-12-02 01:14:01'),
(2, 2, 'Trousers', '2015-12-02 03:31:53'),
(3, 2, 'Underware', '2015-12-04 11:07:46'),
(4, 2, 'Hat', '2015-12-06 11:27:16'),
(5, 2, 'Scarf', '2015-12-07 00:14:31'),
(6, 2, 'Shirt', '2015-12-07 07:17:03'),
(7, 1, 'Shoes', '2015-12-09 16:23:20'),
(8, 1, 'Socks', '2015-12-11 11:40:16'),
(9, 1, 'Sweater', '2015-12-13 05:20:11'),
(10, 1, 'Shorts', '2015-12-13 12:41:31');
ALTER TABLE `orders`
ADD CONSTRAINT `orders_ibfk_1`
FOREIGN KEY (`client_id`)
REFERENCES `clients` (`client_id`)
ON DELETE CASCADE
ON UPDATE CASCADE;
I need to find the orders for the most recent day for a specific client_id, and only 1 client at a time
Example output for client_id 2
client_id | name | description | order_date
-------------------------------------------------------------
2 | Terry Towl | Hat | 2015-12-07
2 | Terry Towl | Scarf | 2015-12-07
The issue is that we dont know the number of orders on that day, nor the date
The only way I can think to do this is to first query the date of the last order for a client, then to run another to find all records for that client on that date, however was hoping to be able to do this in one query.
Does anyone have an idea how to achieve this in one query?
Your idea is basically correct.
select *
from clients c join
orders o
on c.client_id = o.client_id
where c.client_id = $client_id and
o.order_date = (select max(o2.order_date)
from orders o2
where o2.client_id = c.client_id
);

How to calculate sum of two columns from two different tables without where clause?

I am using the following sql statement to sum values from two columns from two different tables. The statement can output but not the desired result.
SELECT
SUM(`_income`.rate) AS Income,
SUM(`_expense`.rate) AS Expense,
SUM(_income.rate)-SUM(_expense.rate) AS Balance
FROM `_expense`, `_income`
My table is here:
CREATE TABLE IF NOT EXISTS `_expense` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`qnty` int(11) NOT NULL,
`rate` int(11) NOT NULL,
`date` date NOT NULL,
`CreatedByPHPRunner` int(11) NOT NULL,
`remarks` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
--
-- Dumping data for table _expense
INSERT INTO `_expense` (`id`, `item`, `qnty`, `rate`, `date`, `CreatedByPHPRunner`, `remarks`) VALUES
(2, 'Maian', 2, 20, '2013-08-15', 0, 'A tui kher mai'),
(3, 'Battery', 1, 2100, '2013-08-15', 0, 'A lian chi');
--
-- Table structure for table _income
CREATE TABLE IF NOT EXISTS `_income` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`items` varchar(100) DEFAULT NULL,
`qnty` int(11) DEFAULT NULL,
`rate` int(11) DEFAULT NULL,
`date` date DEFAULT NULL,
`remarks` varchar(255) DEFAULT NULL,
`CreatedByPHPRunner` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
--
-- Dumping data for table _income
INSERT INTO `_income` (`id`, `items`, `qnty`, `rate`, `date`, `remarks`, `CreatedByPHPRunner`) VALUES
(1, 'TV chhe siam', 1, 1500, '2013-08-15', 'Ka hniam hrep', NULL),
(2, 'First Star', 1, 25, '2013-08-15', 'A loose-in aw', NULL),
(3, 'Mobile Chhe siam', 2, 200, '2013-08-13', 'Nokia chhuak ho a nia', NULL),
(4, 'Internet hman man', 1, 1500, '2013-08-14', 'Ka net min hman sak a', NULL);
This should do it:
select income, expense, income-expense balance
from (select sum(rate) income
from _income) i
JOIN (select sum(rate) expense
from _expense) e