Anyone up to an SQL challenge? Cause all my efforts so far are barely enough to simplify the problem and put it in a question...
Here it goes. In the example below we need to include:
All paid flights
Flights to a country (paid or not) if a person has made another flight to a paid city in that country
It's already tricky, but there is more to it.
If a person flies to a city with no entry fee, but it is located in a
country that DOES have a fee, that flight is still considered paid
and must be included as well.
EDIT: I've added flight 110, which should help reveal unnecessarily added free fligts.
Below is the result set that should come out of the SQL query:
+--------------------------------------------------------------+
| Desired result set |
+--------------------------------------------------------------+
| FlightNumber | ID | Name | LocationID | location.Name |
+--------------------------------------------------------------+
| 102 | 2 | Tom | 500 | NL - NoFee | -> because Tom has a paid flight to Amsterdam
| 103 | 2 | Tom | 501 | Amsterdam (NL) - Fee | -> because Amsterdam is a paid location
| 105 | 4 | Bob | 501 | Amsterdam (NL) - Fee | -> because Amsterdam is a paid location
| 107 | 6 | Bill | 503 | ITA - Fee | -> because ITA is a paid location
| 108 | 7 | Ryan | 503 | ITA - Fee | -> because ITA is a paid location
| 109 | 7 | Ryan | 505 | Venice (ITA) - NoFee | -> because Venice is located inside ITA
+--------------------------------------------------------------+
Does anyone know how get this sweet result set with SQL?
A good place to start:
SELECT flights.FlightNumber, people.ID, people.Name, flights.LocationID, locations.Name
FROM flights
INNER JOIN people ON (people.ID = flights.ID)
INNER JOIN locations ON (locations.LocationID = flights.LocationID)
CREATE/INSERT
CREATE TABLE `people` (
`ID` INT NOT NULL,
`Name` VARCHAR(45) NULL,
PRIMARY KEY (`ID`) );
CREATE TABLE `locations` (
`LocationID` INT NOT NULL,
`Name` VARCHAR(45) NULL,
`EntryFee` TINYINT(1) NULL,
`ParentLocationID` INT NULL,
PRIMARY KEY (`LocationID`) );
CREATE TABLE `flights` (
`FlightNumber` INT NOT NULL,
`ID` INT NULL,
`LocationID` INT NULL,
PRIMARY KEY (`FlightNumber`) ,
INDEX `fk_purchases_buyers_idx` (`LocationID` ASC) ,
INDEX `fk_flights_people1_idx` (`ID` ASC) ,
CONSTRAINT `fk_purchases_buyers`
FOREIGN KEY (`LocationID`)
REFERENCES `locations` (`LocationID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_flights_people1`
FOREIGN KEY (`ID`)
REFERENCES `people` (`ID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
INSERT INTO `people` (`ID`, `Name`) VALUES
(1, 'John'),
(2, 'Tom'),
(3, 'Kate'),
(4, 'Bob'),
(5, 'Mike'),
(6, 'Bill'),
(7, 'Ryan');
INSERT INTO `locations` (`LocationID`, `Name`, `EntryFee`, `ParentLocationID`) VALUES
(500, 'NL - NoFee', 0, NULL),
(501, 'Amsterdam (NL) - Fee', 1, 500),
(502, 'Rotterdam (NL) - NoFee', 0, 500),
(503, 'ITA - Fee', 1, NULL),
(504, 'Rome (ITA) - Fee', 1, 503),
(505, 'Venice (ITA) - NoFee', 0, 503);
INSERT INTO `flights` VALUES
(100, 1, 500),
(101, 1, 502),
(102, 2, 500),
(103, 2, 501),
(104, 3, 500),
(105, 4, 501),
(106, 5, 502),
(107, 6, 503),
(108, 7, 503),
(109, 7, 505),
(110, 6, 502);
Unimportant note: I know this example is not completely logical in a sense of storing countries and cities in the same table and having flight records to a country and to a city. But this is just an example. At least it's more readable than t1.col1-like stuff.
Following should work :
SELECT F.FlightNumber, P.ID, P.Name, F.LocationID, LOC.Name AS Loc_Name
FROM flights F
INNER JOIN people P ON P.ID = F.ID
INNER JOIN (SELECT L1.LocationID, L1.`Name`, L1.`ParentLocationID`
FROM locations L1
LEFT JOIN locations L2 ON L1.`ParentLocationID` = L2.LocationID
WHERE L1.`EntryFee` = 1 OR L2.`EntryFee` = 1) AS LOC ON LOC.LocationID = F.LocationID
UNION
SELECT F.FlightNumber, PAID_FL.ID, PAID_FL.Name, F.LocationID, PAID_FL.Loc_Name
FROM flights F
INNER JOIN (SELECT F.FlightNumber, P.ID, P.Name, LOC.Name AS Loc_Name,LOC.`ParentLocationID` AS LocationID
FROM flights F
INNER JOIN people P ON P.ID = F.ID
INNER JOIN (SELECT L1.LocationID, L1.`ParentLocationID`, L2.`Name`
FROM locations L1
LEFT JOIN locations L2 ON L1.`ParentLocationID` = L2.LocationID
WHERE L1.`EntryFee` = 1 OR L2.`EntryFee` = 1) AS LOC ON LOC.LocationID = F.LocationID) PAID_FL ON F.ID = PAID_FL.ID AND F.LocationID = PAID_FL.LocationID
I didn't do any testing, but I think this will work:
SELECT F.FlightNumber, P.ID, P.Name, L.LocationID, L.Name
FROM flights F
INNER JOIN people P ON P.ID = F.ID
INNER JOIN locations L ON L.LocationID = F.LocationID
WHERE P.ID IN (SELECT F.ID FROM flights F INNER JOIN locations L ON L.LocationID = F.LocationID WHERE L.EntryFee = 1)
See it at SQLFiddle.com.
SELECT x.*
, COALESCE(y.entryfee,x.entryfee,0) fee
FROM locations x
LEFT
JOIN locations y
ON y.parentlocationid = x.locationid;
Related
MySQL Server version: 5.5.41-0+wheezy1 - (Debian)
I've got a MySQL issue that is almost a year old. Have tried a few freelancers and while we got close, it was never totally solved.
I need to find the most recent outbound shipment for every product we have. And in the same row of results, the specific lot (including lot number and expiration date) of the product that was involved in that inventory adjustment.
The most recent version of this query is almost working but it has one fatal flaw (at least one). If the product only ever had one outbound shipment, it won't show up in the results. I'm assuming that is because on line 30 where a comparison is done, which looks like this
AND liai0.LocationInventoryAdjustmentItemID > liai.LocationInventoryAdjustmentItemID
I'm assuming it is because the one and only adjustment for a product couldn't be greater than itself, it fails to be considered by the where clause. I've tested this by adding a second, fake outbound shipment, for a missing product. The query then returns the missing product.
That isn't the only line with a comparison like that. Perhaps the same problem could happen if there was only ever one location for a given product (line 23) and perhaps if there was only ever one lot for a product (line 16).
Here is the latest version of the query:
SELECT
p.`ProductID`,
p.`ProductName`,
lot.`ProductLotID`,
lot.`ExpirationDate`,
lot.`LotNumber`,
lia.`LocationInventoryAdjustmentID`,
lia.`Created`,
liai.`count`
FROM products AS p
INNER JOIN product_lots AS lot ON lot.ProductID = p.ProductID
AND NOT EXISTS (
SELECT 1
FROM product_lots AS lot0
WHERE lot0.ProductID = lot.ProductID
AND lot0.ProductLotID > lot.ProductLotID
)
INNER JOIN product_locations AS pl ON pl.ProductLotID = lot.ProductLotID
AND NOT EXISTS (
SELECT 1
FROM product_locations AS pl0
WHERE pl0.ProductLotID = pl.ProductLotID
AND pl0.ProductLocationID > pl.ProductLocationID
)
INNER JOIN location_inventory_adjustment_items AS liai ON liai.ProductLocationID = pl.ProductLocationID
AND NOT EXISTS (
SELECT 1
FROM location_inventory_adjustment_items AS liai0
WHERE liai0.ProductLocationID = liai.ProductLocationID
AND liai0.LocationInventoryAdjustmentItemID > liai.LocationInventoryAdjustmentItemID
)
INNER JOIN location_inventory_adjustments AS lia ON lia.LocationInventoryAdjustmentID = liai.LocationInventoryAdjustmentID
INNER JOIN location_inventory_adjustment_reasons AS liar ON liar.ReasonID = lia.ReasonID
WHERE liar.`Name` LIKE '%Out-Bound%'
ORDER BY p.ProductID ASC, liai.LocationInventoryAdjustmentID
And now the tables
Table products
ProductID ProductName
1 Banana
2 Apple
3 Orange
4 Shirt
Table product_lots
ProductLotID ProductID ExpirationDate LotNumber
20 1 2022-01-01 Chikita22
21 3 2023-12-01 Florida-9
22 4 NULL HANES-001
23 1 2024-01-01 Chikita24
Table product_locations
ProductLocationID ProductLotID LocationCode LocationType
30 20 A-01-01-01 1
31 21 A-02-01-01 1
32 22 12-03-01-01 2
33 23 A-01-01-01 1
Table location_inventory_adjustment_items
LocationInventoryAdjustmentItemID LocationInventoryAdjustmentID ProductLocationID Count
40 50 30 100
41 51 31 200
42 52 32 300
43 53 33 150
Table location_inventory_adjustments
LocationInventoryAdjustmentID LocationTypeID ReasonID Created
50 1 4 2020-01-01
51 1 4 2020-05-01
52 2 4 2020-06-01
53 1 4 2020-07-07
Table location_inventory_adjustment_reasons
ReasonID Name Description
1 Discarded Product Trash
2 In-Bound Shipment Delivery
3 Out-Bound Shipment Product was shipped out
4 Out-Bound Shipment - FBA US Product was shipped out to an Amazon fulfillment center in the US
5 Out-Bound Shipment - FBA UK Product was shipped out to an Amazon fulfillment center in the UK
Now that the table structure is added, only the product Banana would be returned by the query since it is the only product to be involved in more than one inventory adjustment (more than one outbound shipment).
What can I do to fix this bug (in my query, obviously not a bug in MySQL)
Ican't really explain it it must be one or other restricted wording.
But try, at least mysql 8 workbench doesn't mind
CREATE TABLE products
(`ProductID` int, `ProductName` varchar(6))
;
INSERT INTO products
(`ProductID`, `ProductName`)
VALUES
(1, 'Banana'),
(2, 'Apple'),
(3, 'Orange'),
(4, 'Shirt')
;
✓
✓
CREATE TABLE product_lots
(`ProductLotID` int, `ProductID` int, `ExpirationDate` varchar(10), `LotNumber` varchar(9))
;
INSERT INTO product_lots
(`ProductLotID`, `ProductID`, `ExpirationDate`, `LotNumber`)
VALUES
(20, 1, '2022-01-01', 'Chikita22'),
(21, 3, '2023-12-01', 'Florida-9'),
(22, 4, NULL, 'HANES-001'),
(23, 1, '2024-01-01', 'Chikita24')
;
✓
✓
CREATE TABLE product_locations
(`ProductLocationID` int, `ProductLotID` int, `LocationCode` varchar(11), `LocationType` int)
;
INSERT INTO product_locations
(`ProductLocationID`, `ProductLotID`, `LocationCode`, `LocationType`)
VALUES
(30, 20, 'A-01-01-01', 1),
(31, 21, 'A-02-01-01', 1),
(32, 22, '12-03-01-01', 2),
(33, 23, 'A-01-01-01', 1)
;
✓
✓
CREATE TABLE location_inventory_adjustment_items
(`LocationInventoryAdjustmentItemID` int, `LocationInventoryAdjustmentID` int, `ProductLocationID` int, `Count` int)
;
INSERT INTO location_inventory_adjustment_items
(`LocationInventoryAdjustmentItemID`, `LocationInventoryAdjustmentID`, `ProductLocationID`, `Count`)
VALUES
(40, 50, 30, 100),
(41, 51, 31, 200),
(42, 52, 32, 300),
(43, 53, 33, 150)
;
✓
✓
CREATE TABLE location_inventory_adjustments
(`LocationInventoryAdjustmentID` int, `LocationTypeID` int, `ReasonID` int, `Created` date)
;
INSERT INTO location_inventory_adjustments
(`LocationInventoryAdjustmentID`, `LocationTypeID`, `ReasonID`, `Created`)
VALUES
(50, 1, 4, '2020-01-01'),
(51, 1, 4, '2020-05-01'),
(52, 2, 4, '2020-06-01'),
(53, 1, 4, '2020-07-07')
;
✓
✓
CREATE TABLE location_inventory_adjustment_reasons
(`ReasonID` int, `Name` varchar(27), `Description` varchar(65))
;
INSERT INTO location_inventory_adjustment_reasons
(`ReasonID`, `Name`, `Description`)
VALUES
(1, 'Discarded Product', 'Trash'),
(2, 'In-Bound Shipment', 'Delivery'),
(3, 'Out-Bound Shipment', 'Product was shipped out'),
(4, 'Out-Bound Shipment - FBA US', 'Product was shipped out to an Amazon fulfillment center in the US'),
(5, 'Out-Bound Shipment - FBA UK', 'Product was shipped out to an Amazon fulfillment center in the U')
;
✓
✓
SELECT
p.`ProductID`,
p.`ProductName`,
lot.`ProductLotID`,
lot.`ExpirationDate`,
lot.`LotNumber`,
lia.`LocationInventoryAdjustmentID`,
lia.`Created`,
liai.`count`
FROM products AS p
INNER JOIN product_lots AS lot ON lot.ProductID = p.ProductID
AND NOT EXISTS (
SELECT 1
FROM product_lots AS lot0
WHERE lot0.ProductID = lot.ProductID
AND lot0.ProductLotID > lot.ProductLotID
)
INNER JOIN product_locations AS pl ON pl.ProductLotID = lot.ProductLotID
AND NOT EXISTS (
SELECT 1
FROM product_locations AS pl0
WHERE pl0.`ProductLotID` = pl.`ProductLotID`
AND pl0.ProductLocationID > pl.ProductLocationID
)
INNER JOIN location_inventory_adjustment_items AS liai ON liai.ProductLocationID = pl.ProductLocationID
AND NOT EXISTS (
SELECT 1
FROM location_inventory_adjustment_items AS liai0
WHERE liai0.ProductLocationID = liai.ProductLocationID
AND liai0.`LocationInventoryAdjustmentItemID` > liai.`LocationInventoryAdjustmentItemID`
)
INNER JOIN location_inventory_adjustments AS lia ON lia.LocationInventoryAdjustmentID = liai.LocationInventoryAdjustmentID
INNER JOIN location_inventory_adjustment_reasons AS liar ON liar.ReasonID = lia.ReasonID
WHERE liar.`Name` LIKE '%Out-Bound%'
ORDER BY p.ProductID ASC, liai.LocationInventoryAdjustmentID
ProductID | ProductName | ProductLotID | ExpirationDate | LotNumber | LocationInventoryAdjustmentID | Created | count
--------: | :---------- | -----------: | :------------- | :-------- | ----------------------------: | :--------- | ----:
1 | Banana | 23 | 2024-01-01 | Chikita24 | 53 | 2020-07-07 | 150
3 | Orange | 21 | 2023-12-01 | Florida-9 | 51 | 2020-05-01 | 200
4 | Shirt | 22 | null | HANES-001 | 52 | 2020-06-01 | 300
db<>fiddle here
I am having trouble either getting any result or a correct result in the following problem - http://www.sqlfiddle.com/#!9/696ed2/4
Overall goal is to list all transactions of users who are linked together as 'Customers'. So if John is looking at his dashboard, he will see which books Alice (his customer) has rented (including book title), and which books were sold (he won't be able to see the title of that book).
When two multiple tables are joined to the parent table, where both depending tables have an 'active' flag set against each row, I can't seem to get only active rows.
# USERS
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`active` boolean DEFAULT NULL
);
INSERT INTO `users` (`id`, `name`, `active`) VALUES
(1, 'John', 1),
(2, 'Alice', 1),
(3, 'Jess', 1),
(4, 'Bob', 1);
# BOOKS
CREATE TABLE `books` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`active` boolean DEFAULT NULL
);
INSERT INTO `books` (`id`, `name`, `active`) VALUES
(1, 'On the Road', 1),
(2, 'Neuromancer', 0),
(3, 'Modern History', 1),
(4, 'Red Mars', 1);
# TRANSACTIONS
CREATE TABLE `transactions` (
`id` int(11) NOT NULL,
`user_1_id` int(11) NOT NULL,
`user_2_id` int(11) DEFAULT NULL,
`book_id` int(11) DEFAULT NULL,
`timestamp` varchar(20) DEFAULT NULL,
`type` enum('Rent', 'Sold') NOT NULL
);
INSERT INTO `transactions` (`id`, `user_1_id`, `user_2_id`, `book_id`, `timestamp`, `type`) VALUES
(1, 1, 2, 1, '1465238591', 'Rent'),
(2, 2, 1, 2, '1465238592', 'Rent'),
(3, 2, 3, 3, '1465238593', 'Rent'),
(4, 3, 4, NULL, '1465238594', 'Sold'),
(5, 2, 3, NULL, '1465238595', 'Sold'),
(6, 3, 4, NULL, '1465238596', 'Sold'),
(7, 2, 2, 4, '1465238597', 'Rent'),
(8, 1, 3, 1, '1465238598', 'Rent'),
(9, 2, 4, 2, '1465238598', 'Rent');
# RELATIONSHIPS
CREATE TABLE `relationships` (
`id` int(11) NOT NULL,
`user_1_id` int(11) DEFAULT NULL,
`user_2_id` int(11) NOT NULL,
`type` enum('Customer', 'Supplier') NOT NULL
);
INSERT INTO `relationships` (`id`, `user_1_id`, `user_2_id`, `type`) VALUES
(1, 1, 2, 'Customer'),
(2, 2, 1, 'Customer'),
(3, 2, 4, 'Customer'),
(3, 1, 4, 'Supplier'),
(3, 3, 1, 'Customer');
Query:
SELECT DISTINCT
t.id,
t.type,
t.timestamp,
u1.name as user_1_name,
u2.name as user_2_name,
b.name as book_name
FROM transactions t
LEFT JOIN relationships r ON (r.user_1_id = 1 AND r.type = 'Customer')
LEFT JOIN books b ON (b.id = t.book_id AND b.active)
LEFT JOIN users u1 ON (u1.id = t.user_1_id) # AND u1.active
LEFT JOIN users u2 ON (u2.id = t.user_2_id) # AND u2.active
WHERE (r.user_2_id = t.user_1_id OR t.user_2_id = 1 AND t.user_1_id != 1)
# AND b.active AND u1.active AND u2.active
[Result]:
| id | type | timestamp | user_1_name | user_2_name | book_name |
|----|------|------------|-------------|-------------|----------------|
| 3 | Rent | 1465238593 | Alice | Jess | Modern History |
| 2 | Rent | 1465238592 | Alice | John | (null) | <<< Should not be here
| 7 | Rent | 1465238597 | Alice | Alice | Red Mars |
| 5 | Sold | 1465238595 | Alice | Jess | (null) | <<< Correct
| 9 | Rent | 1465238598 | Alice | Bob | (null) | <<< Should not be here
In the above result, the problem is that book Neuromancer has flag 'active' set to 0, so should not appear in the result. I have played with placing AND b.active at different places, but the results are always wrong. (See http://www.sqlfiddle.com/#!9/696ed2/5)
Looking at the mess above, I am not even sure my approach is any good, any suggestions are welcome.
As D. Smania mentioned in comments you need to make sure b.active is either 1 or NULL but based on your LEFT JOIN condition b.active will always be 1 so you need to do the join only on id and rely on the WHERE condition for comparison. This should yield the results you asked for:
SELECT DISTINCT
t.id,
t.type,
t.timestamp,
u1.name AS user_1_name,
u2.name AS user_2_name,
b.name AS book_name
FROM transactions t
LEFT JOIN relationships r ON (r.user_1_id = 1 AND r.type = 'Customer')
LEFT JOIN books b ON (b.id = t.book_id)
LEFT JOIN users u1 ON (u1.id = t.user_1_id)
LEFT JOIN users u2 ON (u2.id = t.user_2_id)
WHERE (r.user_2_id = t.user_1_id OR t.user_2_id = 1 AND t.user_1_id != 1)
AND (b.active OR b.active IS NULL)
AND u1.active AND u2.active
SQL Fiddle
One note - in your first WHERE condition it's not clear to me whether you mean:
(r.user_2_id = t.user_1_id OR (t.user_2_id = 1 AND t.user_1_id != 1))
or
((r.user_2_id = t.user_1_id OR t.user_2_id = 1) AND t.user_1_id != 1)
It's always best to be explicit with your logic grouping when you have adjacent AND and OR conditions.
I have below tables
tbl_user
uid first_name last_name email_id
1 steve martin steve1#gmail.com
2 mark lee mark1#gmail.com
3 nelson wise nelson23#gmail.com
tbl_tier
tier_id tier_name points_required
1 Silver 100
2 Gold 200
3 Platinum 300
tbl_tier_earned
id tier_id uid
1 1 1
2 2 1
3 3 1
4 1 2
5 2 2
6 1 3
I need unique users with their current tiers like:
first_name last_name email_id current_tier
steve martin steve1#gmail.com Platinum
mark lee mark1#gmail.com Gold
I have tried below query but it gives me only 1 result:
SELECT u.first_name,u.last_name,u.email_id, t.tier_name
FROM tbl_tier_earned AS tte
INNER JOIN tbl_user AS u
ON u.uid = tte.uid
INNER JOIN tbl_tier AS t
ON tte.tier_id = t.tier_id
WHERE u.email_id!=""
ORDER BY t.points_required DESC LIMIT 0,1
How can I retrieve above data using mysql query?
It appears that the current tier is given by the max tier_id in the tbl_tier_earned table, for each user. One approach here would be to join the user table to a subquery on the tbl_tier_earned table which finds the max tier.
SELECT
u.first_name,
u.last_name,
u.email_id,
COALESCE(t2.tier_name, 'NA') AS current_tier
FROM tbl_user u
LEFT JOIN
(
SELECT uid, MAX(tier_id) AS max_tier_id
FROM tbl_tier_earned
GROUP BY uid
) t1
ON u.uid = t1.uid
LEFT JOIN tbl_tier t2
ON t1.max_tier_id = t2.tier_id;
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE tbl_user
(`uid` int, `first_name` varchar(6), `last_name` varchar(6), `email_id` varchar(18))
;
INSERT INTO tbl_user
(`uid`, `first_name`, `last_name`, `email_id`)
VALUES
(1, 'steve', 'martin', 'steve1#gmail.com'),
(2, 'mark', 'lee', 'mark1#gmail.com'),
(3, 'nelson', 'wise', 'nelson23#gmail.com')
;
CREATE TABLE tbl_tier
(`tier_id` int, `tier_name` varchar(8), `points_required` int)
;
INSERT INTO tbl_tier
(`tier_id`, `tier_name`, `points_required`)
VALUES
(1, 'Silver', 100),
(2, 'Gold', 200),
(3, 'Platinum', 300)
;
CREATE TABLE tbl_tier_earned
(`id` int, `tier_id` int, `uid` int)
;
INSERT INTO tbl_tier_earned
(`id`, `tier_id`, `uid`)
VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 1),
(4, 1, 2),
(5, 2, 2),
(6, 1, 3)
;
Query 1:
SELECT c.first_name, c.last_name, c.email_id,
(SELECT tier_name from tbl_tier WHERE points_required = max(b.points_required)) as current_tier
FROM tbl_tier_earned a
INNER JOIN tbl_tier b ON a.tier_id = b.tier_id
INNER JOIN tbl_user c ON a.uid = c.uid
GROUP BY c.first_name, c.last_name, c.email_id
Results:
| first_name | last_name | email_id | current_tier |
|------------|-----------|--------------------|--------------|
| mark | lee | mark1#gmail.com | Gold |
| nelson | wise | nelson23#gmail.com | Silver |
| steve | martin | steve1#gmail.com | Platinum |
Extending Rolling up addition using mysql
I can get rolling sum of rows https://stackoverflow.com/users/1529673/strawberry's answer for basic stuff so i tried to extend query by joining multiple tables but 1_keyworddefs.name='K2' is not affected. Getting same answer for 1_keyworddefs.name='K1' and K2.
Working query but directly by specifying 1_bugs.bug_id='2':
SELECT x.*, x.cf1 + x.cf2 sub_total, sum(y.cf1 + y.cf2) total FROM 1_bugs x INNER JOIN 1_bugs y ON y.bug_id <= x.bug_id INNER JOIN 1_keywords ON 1_keywords.bug_id = y.bug_id WHERE (x.bug_date BETWEEN '2016-07-19' AND '2016-07-22') AND (x.bug_id='2') AND (y.bug_status = 'VERIFIED' OR y.bug_status = 'CLOSED') AND (1_keywords.bug_id = x.bug_id) GROUP BY x.bug_id
Exact output (but i want to join table where 1_keywords.bug_id=1_bugs.bug_id matches instead of directly specifying 1_bugs.bug_id='2'):
bug_id bug_date cf1 cf2 bug_status sub_total total
2 2016-07-19 2 1 VERIFIED 3 3
Non-working query by joining tables (expecting answer like above):
SELECT x.*, x.cf1 + x.cf2 sub_total, sum(y.cf1 + y.cf2) total FROM 1_bugs x INNER JOIN 1_bugs y ON y.bug_id <= x.bug_id LEFT JOIN 1_keywords ON 1_keywords.bug_id = y.bug_id LEFT JOIN 1_keyworddefs ON 1_keyworddefs.id=1_keywords.keywordid AND 1_keyworddefs.name='K2' and 1_keywords.bug_id = y.bug_id WHERE (x.bug_date BETWEEN '2016-07-19' AND '2016-07-22') AND (y.bug_status = 'CLOSED' OR y.bug_status = 'VERIFIED') GROUP BY x.bug_id;
Expected:
bug_id bug_date cf1 cf2 bug_status sub_total total
2 2016-07-19 2 1 VERIFIED 3 3
Actual:
bug_id bug_date cf1 cf2 bug_status sub_total total
2 2016-07-19 2 1 VERIFIED 3 3
3 2016-07-22 2 2 CLOSED 4 7
** Here bug_id -> 3 row comes wrongly because 1_bugs.bug.id=1_keywords.bug_id doesn't match and there is no 1_keywords.bug_id='3' present in 1_keywords table.
DDLs:
-- 1_bugs table1 (master table) :
CREATE TABLE `1_bugs` (`bug_id` int(11) NOT NULL, `bug_date` date NOT NULL, `cf1` int(11) NOT NULL, `cf2` int(11) NOT NULL, `bug_status` varchar(200) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `1_bugs` (`bug_id`, `bug_date`, `cf1`, `cf2`, `bug_status`) VALUES (1, '2016-07-19', 3, 2, 'RESOLVED'), (2, '2016-07-19', 2, 1, VERIFIED'), (3, '2016-07-22', 2, 2, 'CLOSED');
-- 1_keywords table2 (having keyword ids):
CREATE TABLE `1_keywords` (`bug_id` int(11) NOT NULL, `keywordid` varchar(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `1_keywords` (`bug_id`, `keywordid`) VALUES (1, 'K1'), (2, 'K2');
-- 1_keyworddefs table3 (having keyword names according to keywordid):
CREATE TABLE `1_keyworddefs` (`id` int(11) NOT NULL, `name` varchar(200) NOT NULL, `description` varchar(200) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `1_keyworddefs` (`id`, `name`, `description`) VALUES (1, 'K1', 'My K1 item'), (2, 'K2', 'My K2 item');
Can someone please point me what i'm doing wrong?
Obviously things where not clear... after long discussions turns out what you wanted was to extract from bugzilla database a list of bugs for specific keyword grouped by date and a sum of cf1 + cf2 and the same sum of only 'opened' and 'verified' bugs.
Here we go
SELECT
b.lastdiffed,
d.name,
d.description,
SUM(IF(b.bug_status IN('CLOSED', 'VERIFIED'), b.cf1 + b.cf2, 0)) AS sub_total,
SUM(b.cf1 + b.cf2) AS running
FROM
bugs AS b
JOIN keywords AS k
ON ( k.bug_id = b.bug_id )
JOIN keyworddefs AS d
ON ( d.id = k.keywordid )
WHERE
1
AND d.name = 'SONY'
GROUP BY (b.lastdiffed)
ORDER BY b.lastdiffed ASC
Giving this result
+------------+------+-------------+-----------+---------+
| lastdiffed | name | description | sub_total | running |
+------------+------+-------------+-----------+---------+
| 2016-05-20 | SONY | sony items | 7 | 7 |
| 2016-06-20 | SONY | sony items | 11 | 17 |
| 2016-06-27 | SONY | sony items | 5 | 5 |
| 2016-06-29 | SONY | sony items | 5 | 5 |
+------------+------+-------------+-----------+---------+
Hope this helps.
I have two table complain and repair. I want to get ass_to_per [Latest one] from repair or from complain if the id of complain is not present in repair.
Explanation:
I want to get the ass_to_per from the complain table, and also from the repair table. But there is a relation between them, in repair there is a field called com_id which is a foreign key. So i want to get the ass_to_per from complain and also check the repair for the foreign key, if any then check the ass_to_per of repair. If any then get it as result.
I have sqlfiddle, For online testing: sqlfiddle.com
The table and data given below.
Complain
CREATE TABLE `complain` (
`id` int(11) NOT NULL,
`ass_to_per` varchar(50) NOT NULL
);
INSERT INTO `complain` (`id`, `ass_to_per`) VALUES
(1, 'frayne'),
(2, 'murad'),
(4, 'frayne'),
(5, 'murad'),
(6, 'frayne'),
(7, 'frayne');
Repair
CREATE TABLE `repair` (
`id` int(11) NOT NULL,
`com_id` int(11) NOT NULL,
`ass_to_per` varchar(50) NOT NULL
);
INSERT INTO `repair` (`id`, `com_id`, `ass_to_per`) VALUES
(1, 1, 'frayne'),
(2, 1, 'murad'),
(3, 4, 'frayne'),
(4, 6, 'murad'),
(5, 2, 'murad'),
(6, 5, 'frayne');
My Query:
SELECT * FROM `complain`
WHERE `id` IN (SELECT DISTINCT(`com_id`) FROM `repair` WHERE `ass_to_per` = 'frayne') OR `ass_to_per`='frayne'
Query Result
id | ass_to_per
--------------
1 | frayne
4 | frayne
5 | murad
6 | frayne
7 | frayne
Analysis
id | ass_to_per[complain] | ass_to_per[repair]
--------------
1 | murad | frayne
2 | murad | murad
4 | frayne | frayne //need this one
5 | murad | frayne //need this one
6 | frayne | murad
7 | frayne | //need this one
Expected result:
id | ass_to_per
--------------
4 | frayne //ass_to_per from repair
5 | frayne //ass_to_per from repair
7 | frayne //ass_to_per from complain
COALESCE() will output the first non-null parameter it finds, so using a join you can probably get ass_to_per from complain or repair depending on which one exists:
SELECT
complain.id,
COALESCE(repair3.ass_to_per, complain.ass_to_per) as ass_to_per
FROM complain
LEFT JOIN
(SELECT max(id) as maxid, com_id FROM repair GROUP BY com_id) as repair2
ON complain.id = repair2.com_id
LEFT JOIN repair as repair3
ON repair2.maxid = repair3.id
GROUP BY complain.id
If you want to further filter (like in your example on 'frayne') on computed ass_to_per, just embed this select as a subquery:
SELECT *
FROM (
SELECT
complain.id,
COALESCE(repair3.ass_to_per, complain.ass_to_per) as ass_to_per
FROM complain
LEFT JOIN (SELECT max(id) as maxid, com_id FROM repair GROUP BY com_id) AS repair2
ON complain.id = repair2.com_id
LEFT JOIN repair as repair3
ON repair2.maxid = repair3.id
GROUP BY complain.id
) AS mydata
WHERE mydata.ass_to_per = 'frayne'
ORDER BY mydata.id;
Fiddle here : http://sqlfiddle.com/#!9/33433/49
SELECT c.id
FROM complain c
LEFT
JOIN
( SELECT x.*
FROM repair x
JOIN
( SELECT com_id,MAX(id) id FROM repair GROUP BY com_id ) y
ON y.com_id = x.com_id
AND y.id = x.id
) r
ON r.com_id = c.id
WHERE COALESCE(r.ass_to_per,c.ass_to_per) = 'frayne';