How to use group by and count in mysql - mysql

Here I am having 3 table using I have to take the count
trip_details
id allocationId tripId
1 7637 aIz2o
2 7626 osseC
3 7536 01LEC
4 7536 78w2w
5 7640 S60zF
6 7548 ruaoR
7 7548 Qse6s
escort_allocation
id allocationId escortId
3 7637 1
4 7626 1
5 7627 1
6 7536 1
7 7640 1
7 7548 1
cab_allocation
allocationId allocationType
7637 Daily Trip
7626 Daily Trip
7627 Daily Trip
7536 Adhoc Trip
7640 Adhoc Trip
7548 Daily Trip
Using above table I have to get the count, I tried but it is not happening my expected results.
I tried sql query
SELECT a.`tripId`
FROM `trip_details` a
INNER JOIN escort_allocation b ON a.`allocationId` = b.`allocationId`
GROUP BY a.`allocationId`
LIMIT 0 , 30
I am getting like this
tripId
01LEC
ruaoR
osseC
aIz2o
S60zF
total 6 tripId i got ,so now I want to take the count so I am using this query
SELECT COUNT(*)
FROM `trip_details` a
INNER JOIN escort_allocation b ON a.`allocationId` = b.`allocationId`
GROUP BY a.`allocationId`
LIMIT 0 , 30
but this query is not working.I am getting results like below
2
2
1
1
1
MY MYSQL TABLES AND VALUES LOOK LIKE THIS
CREATE TABLE `trip_details` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`allocationId` int(11) NOT NULL,
`tripId` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `tripId` (`tripId`),
KEY `allocationId` (`allocationId`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1 ;
INSERT INTO trip_details
(id, allocationId, tripId)
VALUES
(1, 7637, '00SwM'),
(2, 7626, '00SwM'),
(3, 7536, '00SwM'),
(4, 7536, '01hEU'),
(5, 7640, '01hEU'),
(6, 7548, 'IRZMS'),
(7, 7548, 'IRZMS');
CREATE TABLE `escort_allocation` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`allocationId` int(11) NOT NULL,
`escortId` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1 ;
INSERT INTO escort_allocation
(id, allocationId, escortId)
VALUES
(1, 7637, 'ssda'),
(2, 7626, 'adad'),
(3, 7627, 'sfsaf'),
(4, 7536, 'ssaf'),
(5, 7640, 'asf'),
(6, 7548, 'a3r');
CREATE TABLE `cab_allocation` (
`allocationId` int(11) NOT NULL AUTO_INCREMENT,
`allocationType` enum('Daily Trip','Adhoc Trip') NOT NULL,
PRIMARY KEY (`allocationId`)
) ENGINE=InnoDB AUTO_INCREMENT=7695 DEFAULT CHARSET=latin1;
INSERT INTO cab_allocation
(allocationId, allocationType)
VALUES
(7637, 'Daily Trip'),
(7626, 'Daily Trip'),
(7627, 'Daily Trip'),
(7536, 'Adhoc Trip'),
(7640, 'Adhoc Trip'),
(7548, 'Daily Trip');

You can try this
SELECT COUNT(DISTINCT (a.`tripId`))
FROM `trip_details` a
INNER JOIN escort_allocation b ON a.`allocationId`=b.`allocationId`
LIMIT 0 , 30
because of GROUP BY there is separate count for all allocationId.

With this, you should get the tripid and the amount:
SELECT COUNT(a.tripId) as total, a.tripId as tripId
FROM trip_details a INNER JOIN escort_allocation b
ON a.allocationId = b.allocationId
GROUP BY a.allocationId LIMIT 0 , 30

You may use:
SELECT COUNT(DISTINCT a.allocationId)
FROM
trip_details a
INNER JOIN
escort_allocation b
ON a.allocationId = b.allocationId
Previously you used COUNT(*) and also used GROUP BY so the counts of rows you were getting are from individual groups.
Update-2:
SELECT
(
SELECT COUNT(*) FROM trip_details
) AS Total_Trip_Count,
COUNT(T.tripId) as Escort_Count,
(
SELECT COUNT(*) FROM
(
SELECT a.allocationId
FROM escort_allocation a
INNER JOIN cab_allocation c ON a.allocationId = c.allocationId
WHERE c.allocationType = 'Adhoc Trip'
GROUP BY a.allocationId
) AS Ad
) AS Adhoc_Trip_Count
FROM
(
SELECT a.tripId FROM
trip_details a
INNER JOIN
escort_allocation b
ON a.allocationId = b.allocationId
GROUP BY a.allocationId
) AS T

Related

How to join two table to get day sale

I want to join two table with some condition
Table 1
CREATE TABLE IF NOT EXISTS `payment` (
`paymentcode` int(6) NOT NULL,
`date` int(3) unsigned NOT NULL,
`amount` varchar(200) NOT NULL,
`customer` varchar(200) NOT NULL,
`store` varchar(200) NOT NULL
)
('2', '20190120', '10050','C1','A'),
('2', '20190120', '10050','c2','A'),
('6', '20190120', '9050','c3','A'),
('4', '20190120', '9045','c4','B'),
('6', '20190121', '10050','c5','B'),
('2', '20190121', '20050','c6','A');
Table 2
CREATE TABLE IF NOT EXISTS `customer` (
`code` int(6) NOT NULL,
`name` int(3) NOT NULL,
)
( 'C1','Customer1'),
( 'c2','Customer2'),
( 'c3','Customer3'),
( 'c4','Customer4'),
( 'c5','Customer5'),
( 'c6','Customer6');
select a.date,a.Paymentcode,a.store,b.Amount as document_total
from
(select date ,Paymentcode,store,sum(amount) from payment
group by date ,Paymentcode,store
) a
join
(select date ,store, sum(amount)as Amount from Payment
group by date ,store) b
on a.date = b.date and a.store = b.store
From above query I can fetch below value:
date paymentcode Amount documet_total
20190120 2 20100 29150
20190120 4 9045 9045
20190120 6 18095 29150
20190121 4 20050 20050
20190121 2 10050 10050
This was the query I was trying. Now I want to JOIN customer table to get customer code if Paymentcode='2' else need to take store value
My expected out is below:
date paymentcode Amount customer_type document_total
20190120 2 10050 C1 29150
20190120 2 10050 C2 29150
20190120 4 9045 B 9045
20190120 6 18095 A 29150
20190121 4 20050 B 20050
20190121 2 10050 C6 10050
Where I need to calculate amount based on date,store,customer_type and Paymentcode, customer_type should customercode it paymentcode='2' else store code, document_total is based on date,store.
Please advice me how to join these table and get the output

Find diff between MySQL tables, only returning rows where a specific column has changed

I need to diff two MysQL tables, and report on changes to a subset of the results.
Let's say I have these two tables:
Table A:
id name supplier value
-----------------------------------------
1 Alice X 100
2 Bob Y 200
3 Clare Z 300
4 Desmond X 400
Table B:
id name supplier value
-----------------------------------------
1 Alice X 150
2 Bob X 200
3 Clare Z 350
4 Desmond X 400
5 Emily X 500
I'm interested in changes to any row involving supplier X. Given the above, I want to return:
ID 1, because the supplier is X and the value has changed;
ID 2, because the supplier has changed from Y to X;
ID 5, because the supplier is X and there's no corresponding row in table A.
I'm not interested in ID 3 because, while the value has changed, the change doesn't involve supplier X. I'm also not interested
in ID 4 because there is no change at all.
I can use UNION ALL to compute the diff:
SELECT *
FROM
(
SELECT a.id, a.name, a.supplier, a.value, 'a' as tbl
FROM a
UNION ALL
SELECT b.id, b.name, b.supplier, b.value, 'b' as tbl
FROM b
) t
GROUP BY id, name, supplier, value
HAVING COUNT(*) = 1
ORDER BY id
This returns all rows where the data has changed:
id name supplier value tbl
---------------------------------------------------
1 Alice X 100 a
1 Alice X 150 b
2 Bob Y 200 a
2 Bob X 200 b
3 Clare Z 300 a
3 Clare Z 350 b
5 Emily X 500 b
However, it is also including ID 3 which I'm not interested in, because neither the row from table A or B has supplier X.
So finally, my question is - how to return results where one of the diffed rows is supplier X? I could of course filter the results in code, but it would be great to do this in a single query.
I would approach it using two LEFT JOINS with a UNION:
CREATE TABLE `a` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT '0',
`supplier` VARCHAR(50) NOT NULL DEFAULT '0',
`value` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=5
;
CREATE TABLE `b` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT '0',
`supplier` VARCHAR(50) NOT NULL DEFAULT '0',
`value` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=6
;
INSERT INTO `a` (`id`, `name`, `supplier`, `value`) VALUES (1, 'Alice', 'X', 100);
INSERT INTO `a` (`id`, `name`, `supplier`, `value`) VALUES (2, 'Bob', 'Y', 200);
INSERT INTO `a` (`id`, `name`, `supplier`, `value`) VALUES (3, 'Clare', 'Z', 300);
INSERT INTO `a` (`id`, `name`, `supplier`, `value`) VALUES (4, 'Desmond', 'X', 400);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (1, 'Alice', 'X', 150);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (2, 'Bob', 'X', 200);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (3, 'Clare', 'Z', 350);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (4, 'Desmond', 'X', 400);
INSERT INTO `b` (`id`, `name`, `supplier`, `value`) VALUES (5, 'Emily', 'X', 500);
SELECT a.name AS name, a.supplier AS a_supplier, a.value AS a_value, b.supplier AS b_supplier, b.value AS b_value FROM a
LEFT JOIN b ON a.name = b.name
WHERE (a.supplier ='X' OR b.supplier = 'X') AND (a.value <> b.value OR a.supplier <> b.supplier OR b.name IS NULL)
UNION
SELECT b.name AS name, a.supplier AS a_supplier, a.value AS a_value, b.supplier AS b_supplier, b.value AS b_value FROM b
LEFT JOIN a ON b.name = a.name
WHERE (a.supplier ='X' OR b.supplier = 'X') AND (a.value <> b.value OR a.supplier <> b.supplier OR a.name IS NULL)
First, you join table A to table B, second you do a reverse join.
I'm not sure whether you can join the tables by their ids, so I used names as a join column for this example.
Every join includes a WHERE clause which filters the rows using your cirteria: "changes to any row involving supplier X".
Here is an SQLFiddle: http://sqlfiddle.com/#!9/46f213/1
You can likely add some where clauses to your original query to check for Supplier X but I think I'd take a slightly different approach and use a join:
SELECT a.id, a.name, a.supplier, a.value, b.name, b.supplier, b.value
FROM a
INNER JOIN b ON (a.id = b.id AND (a.name != b.name OR a.value != b.value OR a.supplier != b.supplier))
WHERE a.supplier = 'X' OR b.supplier = 'X'
GROUP BY a.id;
This gets rows that have changed but only those related to X. Note that this assumes there is always exactly one matching id in each table.
Extending lldar's answer, you could also get the difference by hashing your columns and then looking for changes.
md5(concat(A.`Name`,A.`Supplier`, A.`Value`)) <> md5(concat(b.`Name`,b.`Supplier`,b.`Value`))
this is helpful if you have many columns. Ideally on a longer term, you may edit the tables and add the hash as "computed/calculated" column.
then it would be simply A.hash <> b.hash
requirement could be achieved by using LEFT JOIN only
SELECT b.NAME AS NAME,
a.supplier AS a_supplier,
a.value AS a_value,
b.supplier AS b_supplier,
b.value AS b_value
FROM b
LEFT JOIN a
ON ( a.id = b.id )
WHERE ( b.supplier = 'X'
OR a.supplier = 'X' )
AND ( a.supplier != b.supplier
OR a.value != b.value
OR a.id IS NULL )
ORDER BY b.id;

Mysql select from one table

My Table structure is
id;product_id;sell_type;sell_state
sell_type: BUY, SELL
sell_state: OPEN, FILLED, CANCELED
How to select only product_id with each 2 operation, BUY & SELL in sell_type and FILLED in sell_state
CREATE TABLE `orderlist` (
`id` int(10) UNSIGNED NOT NULL,
`product_id` int(11) NOT NULL,
`sell_type` enum('BUY','SELL') DEFAULT NULL,
`sell_state` enum('OPEN','FILLED','CANCELED') DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `orderlist` (`id`, `product_id`, `sell_type`, `sell_state`) VALUES
(7, 1, 'BUY', 'FILLED'),
(8, 1, 'SELL', 'FILLED'),
(9, 2, 'BUY', 'FILLED'),
(10, 3, 'SELL', 'FILLED');
You could use a group by and count(distinct sell_state) = 2
select product_id
from orderlist
where sell_state ='FILLED'
and sell_type in ('BUY', 'SELL')
group by product_id
having count(distinct sell_type) = 2
http://sqlfiddle.com/#!9/c41301/2
try this select query
SELECT t1.*
FROM temp t1
INNER JOIN temp t2
ON t1.product_id = t2.product_id AND FIND_IN_SET('FILLED',t1.sell_state) > 0
WHERE FIND_IN_SET('BUY',t1.sell_type) > 0 AND
CONCAT(",", t2.sell_type, ",") REGEXP ",(BUY|SELL),"
GROUP BY t1.product_id
demo : http://sqlfiddle.com/#!9/7fcd9/64
try this
SELECT product_id
FROM orderlist
WHERE sell_state = 'FILLED' AND sell_type IN ('BUY','SELL')
GROUP BY product_id
HAVING COUNT(product_id) > 2
demo: http://sqlfiddle.com/#!9/464959/2

mysql | Facet search advanced

I have tables:
CREATE TABLE IF NOT EXISTS `category` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `category` (`id`, `name`) VALUES
(1, 'Computers'),
(2, 'Bikes');
CREATE TABLE IF NOT EXISTS `fields` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`field_name` varchar(255) DEFAULT NULL,
`cid` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
INSERT INTO `fields` (`id`, `field_name`, `cid`) VALUES
(1, 'Processor', '1'),
(2, 'Display', '1'),
(3, 'Brand', '2');
CREATE TABLE IF NOT EXISTS `fields_values` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`field_id` int(11) DEFAULT NULL,
`field_value` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
INSERT INTO `fields_values` (`id`, `field_id`, `field_value`) VALUES
(1, 1, 'Intel Pentium 3'),
(2, 2, '27 inch'),
(3, 3, 'BMX'),
(4, 1, 'AMD Radeon'),
(5, 1, 'Intel Atom'),
(6, 2, '22 inch');
CREATE TABLE IF NOT EXISTS `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`cid` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;
INSERT INTO `products` (`id`, `name`, `cid`) VALUES
(1, 'Computer1', 1),
(2, 'Bike1.BMX', 2),
(3, 'Bike3', 2),
(4, 'Intel Atom', 1),
(5, 'Computer Radeon', 1);
CREATE TABLE IF NOT EXISTS `products_to_fields_values` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) DEFAULT NULL,
`field_value_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
INSERT INTO `products_to_fields_values` (`id`, `product_id`, `field_value_id`) VALUES
(1, 1, 1),
(2, 2, 3),
(3, 1, 2),
(4, 4, 5);
My request looks like:
SELECT ft.id field_id, ft.field_name, fvt.field_value, fvt.id field_value_id, COUNT( DISTINCT pid ) count
FROM FIELDS ft
JOIN fields_values fvt ON ( ft.id = fvt.field_id )
JOIN products_to_fields_values pfv ON ( pfv.field_value_id = fvt.id )
JOIN products pt ON ( pt.id = pfv.product_id )
LEFT JOIN (
SELECT ft.id field_id, ft.field_name, fvt.field_value, fvt.id field_value_id, pt.name, pt.id pid
FROM FIELDS ft
JOIN fields_values fvt ON ( ft.id = fvt.field_id )
JOIN products_to_fields_values pfv ON ( pfv.field_value_id = fvt.id )
JOIN products pt ON ( pt.id = pfv.product_id )
GROUP BY pt.id
)LJ ON pfv.product_id = LJ.pid
WHERE FIND_IN_SET( 1, pt.cid )
GROUP BY ft.field_name, fvt.field_value
LIMIT 0 , 30
This request will return (I'm trying to build faceted filter):
field_id field_name field_value field_value_id count
2 Display 27 inch 2 1
1 Processor Intel Atom 5 1
1 Processor Intel Pentium 3 1
But I have other values in this table: fields_values like: AMD Radeon and 22 inch.
Where is my mistake in the request?
Thanks!
EDIT:
I'm expect to getting result:
field_id field_name field_value field_value_id count
2 Display 22 inch 6 0
2 Display 27 inch 2 1
1 Processor AMD Radeon 4 0
1 Processor Intel Atom 5 1
1 Processor IntelPentium3 1 1
Where count is a products count.
Here is a work SQL, but im not sure you have build your structure correctly.
SELECT
ft.id field_id, ft.field_name, fvt.field_value, fvt.id as field_value_id, COUNT( DISTINCT pid ) count
FROM products AS pt
JOIN products_to_fields_values AS pfv ON pfv.product_id = pt.id
JOIN fields_values AS fvt ON fvt.field_id = pfv.field_value_id
JOIN fields AS ft on ft.id = fvt.field_id
LEFT JOIN (
SELECT ft.id field_id, ft.field_name, fvt.field_value, fvt.id field_value_id, pt.name, pt.id pid
FROM fields ft
JOIN fields_values fvt ON ( ft.id = fvt.field_id )
JOIN products_to_fields_values pfv ON ( pfv.field_value_id = fvt.id )
JOIN products pt ON ( pt.id = pfv.product_id )
GROUP BY pt.id
)LJ ON pfv.product_id = LJ.pid
WHERE FIND_IN_SET( 1, pt.cid )
GROUP BY ft.field_name, fvt.field_value
LIMIT 0 , 30
In short - u have error in this line:
JOIN products_to_fields_values pfv ON ( pfv.field_value_id = fvt.id )
right one:
JOIN products_to_fields_values pfv ON ( pfv.field_value_id = fvt.field_id )
I tried for your question, check this query
select fValue.field_id, f.field_name as field_name, fValue.field_value, fValue.id as field_value_id
from products_to_fields_values as productValue
left join fields_values as fValue on(fValue.field_id=productValue.field_value_id)
left join fields as f on (fValue.field_id=f.id)
left join products as p on (productValue.product_id=p.id)
where p.cid=1
I am quite sure the problem, i.e. the 'missing' records, is being caused by the 'group by' commands. It's a bit difficult to come up with a solution for you as I am not too sure what you are trying to achieve. The expected result you posted hasn't helped me much in this regard. The query you are trying to run is rather complex, and on a populated database is going to start running very, very slowly. As such it would suggest a better database design is required. If you can explain what you are trying to achieve I will gladly look at a solution for you.
Ignoring the limit and where clauses this is the query you need to use:
SELECT
fields.id AS field_id
, fields.field_name
, fields_values.field_value
, fields_values.id AS field_value_id
, COUNT(products.id) AS `count`
FROM fields_values
JOIN fields ON fields.id = fields_values.field_id
JOIN category AS field_category ON field_category.id = fields.cid
LEFT JOIN products_to_fields_values AS product_fields ON fields_values.id = product_fields.field_value_id
LEFT JOIN products ON products.id = product_fields.product_id
GROUP BY 1, 2, 3, 4;
This produces the following result:
| field_id | field_name | field_value | field_value_id | count |
+----------+------------+-----------------+----------------+-------+
| 1 | Processor | AMD Radeon | 4 | 0 |
| 1 | Processor | Intel Atom | 5 | 1 |
| 1 | Processor | Intel Pentium 3 | 1 | 1 |
| 2 | Display | 22 inch | 6 | 0 |
| 2 | Display | 27 inch | 2 | 1 |
| 3 | Brand | BMX | 3 | 1 |
In your where clause you can specify
WHERE category.id IN (1)
to get the result you want.
The mistake you were making (and a previous answer as well) was that you were joining the category through the product giving you the product_category instead of the field_category.
When you applied a where condition on the product_category, it removed all products not part of the set, so you would never get the count = 0

How can I perform an AND operation on a single column?

I have a table with two columns;
CREATE TABLE IF NOT EXISTS `QUESTION_CATEGORY_RELATION` (
`question_id` int(16) NOT NULL,
`category_id` int(16) NOT NULL,
KEY `category_id` (`category_id`),
KEY `question_id` (`question_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `QUESTION_CATEGORY_RELATION` (`question_id`, `category_id`) VALUES
(1, 2),
(1, 3),
(2, 1),
(2, 2);
I want to create a query that will search for a question_id with content_id 2 and content_id 3
e.g.:
SELECT *
FROM `QUESTION_CONTENTS_REL`
WHERE `content_id` = 2 AND `content_id` = 3
SELECT question_id
FROM QUESTION_CONTENTS_REL
WHERE content_id in (2, 3)
group by question_id
having count(distinct content_id) = 2
I might be missinterpreting but i think you are looking for OR instead since the content_id is a key
SELECT * FROM QUESTION_CONTENTS_REL WHERE `content_id`= 2 OR `content_id` = 3
You can try this:
SELECT q1.question_id
FROM `QUESTION_CONTENTS_REL` q1
JOIN `QUESTION_CONTENTS_REL` q2 on q1.question_id=q2.question_id
WHERE q1.`content_id` = 2
AND q2.`content_id` = 3
This is not the nicest solution available, as it has a JOIN, for example in Oracle, I'd do this:
SELECT q.question_id
FROM `QUESTION_CONTENTS_REL` q
GROUP BY q.`question_ID`
HAVING SUM(case when q.`content_id` = '2' then 1 else 0 end)>0
AND SUM(case when q.`content_id` = '2' then 1 else 0 end)>0