How select multiple value in one record in mysql? - mysql

I have a table with many column. one of this contain multiple argument, How can I select a field with one of this argument. for example my query is :
select name from product where product='carpet' and selling='new';
selling column contain 'new' , 'discounted', ..

You are looking for FIND_IN_SET
Returns a value in the range of 1 to N if the string str is in the
string list strlist consisting of N substrings. A string list is a
string composed of substrings separated by , characters
mysql> DESCRIBE products;
+---------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| product | varchar(255) | YES | | NULL | |
| selling | varchar(255) | YES | | NULL | |
+---------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM products;
+----+---------+---------------------------+
| id | product | selling |
+----+---------+---------------------------+
| 1 | carpet | new,discounted,hello,worl |
| 2 | fork | used,other |
| 3 | plate | new |
| 4 | spoon | NULL |
+----+---------+---------------------------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM products
-> WHERE product='carpet' AND FIND_IN_SET('new', selling) <> 0;
+----+---------+---------------------------+
| id | product | selling |
+----+---------+---------------------------+
| 1 | carpet | new,discounted,hello,worl |
+----+---------+---------------------------+
1 row in set (0.00 sec)

Like #BentCoder has rightly answered, MySQL has a dedicated function FIND_IN_SET() that returns the field index, if the value is found in a string containing comma-separated values.
SELECT * FROM products where product = 'carpet' and 'new' like concat('%',selling,'%');
Or you could also try this by adding commas to the left and right:
select * from products where product= 'carpet' and CONCAT(',', selling, ',') like '%,new,%'

Related

Mysql: How to create a column which is the difference between a column in a Table & another column in a View

In the database 'college2' there are 3 TABLES:'student, course & enrolment', and one(1) VIEW:'enrolment_status', which is created using the following command:
CREATE VIEW enrolment_status AS
SELECT code, COUNT(id)
FROM enrolment
GROUP BY code;
Explain command for 'course,enrolment and enrolment_status' results in:
mysql> EXPLAIN course;
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| code | char(8) | NO | PRI | NULL | |
| name | varchar(90) | YES | MUL | NULL | |
| max_enrolment | char(2) | YES | | NULL | |
+---------------+-------------+------+-----+---------+-------+
3 rows in set (0.09 sec)
mysql> explain enrolment;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | char(6) | YES | MUL | NULL | |
| code | char(8) | YES | MUL | NULL | |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.02 sec)
mysql> explain enrolment_status;
+-----------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------+------+-----+---------+-------+
| code | char(8) | YES | | NULL | |
| COUNT(id) | bigint(21) | NO | | 0 | |
+-----------+------------+------+-----+---------+-------+
2 rows in set (0.18 sec)
'max_enrolment' column in 'course' TABLE is the maximum allowed # of student for each course, say 10 or 20.
'count(id)' column in 'enrolment_status' VIEW (not table) is actual # of students enrolled in each course.
'id' column in 'enrolment' TABLE is the student id enrolled in a course.
HERE'S MY QUESTION:
I want to have the '# of seats left' which is the difference between 'max_enrolment' column and 'count(id)' column.
'#of seats left' can be a stand alone table or view or a column added to any of the above tables. How can i do this:
I tried many commands including the following,
CREATE VIEW seats_left AS (
SELECT course.code, course.max_enrolment - enrolment_status.count
FROM course, enrolment_status
WHERE course.code = enrolment_status.code);
...which gives me the following error message:
ERROR 1054 (42S22): Unknown column 'enrolment_status.count' in 'field list'
mysql> SELECT*FROM enrolment_status;
+----------+-----------+
| code | COUNT(id) |
+----------+-----------+
| COMP9583 | 7 |
| COMP9585 | 9 |
| COMP9586 | 7 |
| COMP9653 | 7 |
| COMP9654 | 7 |
| COMP9655 | 8 |
| COMP9658 | 7 |
+----------+-----------+
7 rows in set (0.00 sec)
mysql> SELECT code, max_enrolment FROM course;
+----------+---------------+
| code | max_enrolment |
+----------+---------------+
| COMP9583 | 10 |
| COMP9585 | 15 |
| COMP9586 | 15 |
| COMP9653 | 12 |
| COMP9654 | 10 |
| COMP9655 | 12 |
| COMP9658 | 12 |
+----------+---------------+
7 rows in set (0.00 sec)
+----------+---------------------+
| code | max_enrolment - cnt |
+----------+---------------------+
| COMP9583 | 9 |
| COMP9585 | 14 |
| COMP9586 | 14 |
| COMP9653 | 11 |
| COMP9654 | 9 |
| COMP9655 | 11 |
| COMP9658 | 11 |
+----------+---------------------+
7 rows in set (0.09 sec)
Try to use an acronym for in the view.
CREATE VIEW enrolment_status AS
SELECT code, COUNT(id) count
FROM enrolment
GROUP BY code;
Then you should be able to do this:
CREATE VIEW seats_left AS (
SELECT course.code, course.max_enrolment - enrolment_status.count
FROM course, enrolment_status
WHERE course.code = enrolment_status.code);
If you cannot change the view, then you must use the exact same name in the query:
CREATE VIEW seats_left AS (
SELECT course.code, course.max_enrolment - enrolment_status.'count(id)'
FROM course, enrolment_status
WHERE course.code = enrolment_status.code);
Try this:
SELECT b.`code`,max_enrolment - cnt from
(select `code`, cnt from
(select count(1) as cnt,`code` from enrolment_status
GROUP BY `code`) as a) as a
LEFT JOIN
(SELECT code,max_enrolment from course) as b
on a.`code` = b.`code`
You can change left join to right join

mysql natural join not working

I have two tables in mysql server. I use these tables for studing JOIN multiple tables but something appears to be incorrect:
mysql> select * from category;
+-------------+-----------+
| category_id | name |
+-------------+-----------+
| 1 | fruit |
| 2 | vegetable |
+-------------+-----------+
2 rows in set (0.00 sec)
mysql> desc category;
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| category_id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
And:
mysql> select * from goods;
+---------+--------+-------------+------+
| good_id | name | category_id | cost |
+---------+--------+-------------+------+
| 1 | banan | 1 | 1.00 |
| 2 | potato | 2 | 1.00 |
| 3 | peach | 1 | 1.00 |
+---------+--------+-------------+------+
3 rows in set (0.00 sec)
mysql> desc goods;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| good_id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| category_id | int(11) | NO | MUL | NULL | |
| cost | decimal(6,2) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
The second table has foreign key (category_id) and I can join them using INNER JOIN:
mysql> select c.name category, g.name, g.cost from category as c INNER JOIN goods g ON c.category_id = g.category_id;
+-----------+--------+------+
| category | name | cost |
+-----------+--------+------+
| fruit | banan | 1.00 |
| vegetable | potato | 1.00 |
| fruit | peach | 1.00 |
+-----------+--------+------+
3 rows in set (0.00 sec)
I tried to use NATURAL JOIN but it didnt work and it seems I dont know why(((
mysql> select c.name, g.name, g.cost from category as c NATURAL JOIN goods g;
Empty set (0.00 sec)
Could somebody explain why NATURAL JOIN does not work?
I was having the exact same thing happen to me, and my Googling led me to this question. I eventually figured it out, so I figured I'd post my answer here.
This was the culprit:
Instead of specifying a join condition through ON, USING or a WHERE clause, the NATURAL keyword tells the server to match up any column names between the two tables, and automatically use those columns to resolve the join.
Your fruit and category tables both have a column called "name". When SQL tries to join the two, it tries to join all like columns. So thus, category_id==category_id, but name!=name.
Rename your columns tablename_column instead.

mysql subquery understanding

I am trying to find all sale_id's that have an entry in sales_item_taxes table, but do NOT have a corresponding entry in the sales_items table.
mysql> describe phppos_sales_items_taxes;
+------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+-------+
| sale_id | int(10) | NO | PRI | NULL | |
| item_id | int(10) | NO | PRI | NULL | |
| line | int(3) | NO | PRI | 0 | |
| name | varchar(255) | NO | PRI | NULL | |
| percent | decimal(15,3) | NO | PRI | NULL | |
| cumulative | int(1) | NO | | 0 | |
+------------+---------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
mysql> describe phppos_sales_items;
+--------------------+----------------+------+-----+--------------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+----------------+------+-----+--------------+-------+
| sale_id | int(10) | NO | PRI | 0 | |
| item_id | int(10) | NO | PRI | 0 | |
| description | varchar(255) | YES | | NULL | |
| serialnumber | varchar(255) | YES | | NULL | |
| line | int(3) | NO | PRI | 0 | |
| quantity_purchased | decimal(23,10) | NO | | 0.0000000000 | |
| item_cost_price | decimal(23,10) | NO | | NULL | |
| item_unit_price | decimal(23,10) | NO | | NULL | |
| discount_percent | int(11) | NO | | 0 | |
+--------------------+----------------+------+-----+--------------+-------+
9 rows in set (0.00 sec)
mysql>
Proposed Query:
SELECT DISTINCT sale_id
FROM phppos_sales_items_taxes
WHERE item_id NOT IN
(SELECT item_id FROM phppos_sales_items WHERE sale_id = phppos_sales_items_taxes.sale_id)
The part I am confused by is the subquery. The query seems to work as intended but I am not understanding the subquery part. How does it look for each sale?
For example if I have the following data:
mysql> select * from phppos_sales;
+---------------------+-------------+-------------+---------+-------------------------+---------+--------------------+-----------+-----------+------------+---------+-----------+-----------------------+-------------+---------+
| sale_time | customer_id | employee_id | comment | show_comment_on_receipt | sale_id | payment_type | cc_ref_no | auth_code | deleted_by | deleted | suspended | store_account_payment | location_id | tier_id |
+---------------------+-------------+-------------+---------+-------------------------+---------+--------------------+-----------+-----------+------------+---------+-----------+-----------------------+-------------+---------+
| 2014-08-09 17:53:38 | NULL | 1 | | 0 | 1 | Cash: $12.96<br /> | | | NULL | 0 | 0 | 0 | 1 | NULL |
| 2014-08-09 17:56:59 | NULL | 1 | | 0 | 2 | Cash: $12.96<br /> | | | NULL | 0 | 0 | 0 | 1 | NULL |
+---------------------+-------------+-------------+---------+-------------------------+---------+--------------------+-----------+-----------+------------+---------+-----------+-----------------------+-------------+---------+
mysql> select * from phppos_sales_items;
+---------+---------+-------------+--------------+------+--------------------+-----------------+-----------------+------------------+
| sale_id | item_id | description | serialnumber | line | quantity_purchased | item_cost_price | item_unit_price | discount_percent |
+---------+---------+-------------+--------------+------+--------------------+-----------------+-----------------+------------------+
| 2 | 1 | | | 1 | 1.0000000000 | 10.0000000000 | 12.0000000000 | 0 |
+---------+---------+-------------+--------------+------+--------------------+-----------------+-----------------+------------------+
1 row in set (0.00 sec)
mysql> select * from phppos_sales_items_taxes;
+---------+---------+------+-----------+---------+------------+
| sale_id | item_id | line | name | percent | cumulative |
+---------+---------+------+-----------+---------+------------+
| 1 | 1 | 1 | Sales Tax | 8.000 | 0 |
| 2 | 1 | 1 | Sales Tax | 8.000 | 0 |
+---------+---------+------+-----------+---------+------------+
2 rows in set (0.00 sec)
When I run the query below it does find sale_id 1. But how does the subquery know to filter correctly. I guess I am not understanding how the sub query works.
mysql> SELECT DISTINCT sale_id
-> FROM phppos_sales_items_taxes
-> WHERE item_id NOT IN
-> (SELECT item_id FROM phppos_sales_items WHERE sale_id = phppos_sales_items_taxes.sale_id)
-> ;
+---------+
| sale_id |
+---------+
| 1 |
+---------+
1 row in set (0.00 sec)
Duffy356 link to the SQL-Joins is good, but sometimes seeing with your own data might sometimes make more sense...
First, your query as written and obviously learning will be very expensive to the engine. How it knows what to include is because it is doing a correlated sub-query -- meaning that FOR every record IN the sales_items_taxes table it is running a query TO the sales_items table, which is returning every item possible for said sale_id. Then it comes back to the main query and compares it to the sales_items_taxes table. If it does NOT find it, it allows the sale_id to be included in the result set. Then it goes to the next record in the sales_items_taxes table.
(Your query reformatted for better readability)
SELECT DISTINCT
sale_id
FROM
phppos_sales_items_taxes
WHERE
item_id NOT IN ( SELECT item_id
FROM phppos_sales_items
WHERE sale_id = phppos_sales_items_taxes.sale_id)
Now, think about this. You have 1 sale with 100 items. It is running the correlated sub-query 100 times. Now do this with 1,000 sales id entries and each has however many items, gets expensive quickly.
A better alternative is to take advantage of databases and do a left-join. The indexes work directly with the LEFT JOIN (or inner join) and are optimized by the engine. Also, notice I am using "aliases" for the tables and qualifying the aliases for readability. By starting with your sales items taxes table (the one you are looking for extra entries) is the basis. Now, left-join this sales items table on the two key components of the sale_id and item_id. I would suggest that each table has an index ON (sale_id, item_id) to match the join condition here.
SELECT DISTINCT
sti.sale_id
FROM
phppos_sales_items_taxes sti
LEFT JOIN phppos_sales_items si
ON sti.sale_id = si.sale_id
AND sti.item_id = si.item_id
WHERE
si.sale_id IS NULL
So, from here, think of it that each table is lined-up side-by-side with each other and all you are getting are those on the left side (sale items taxes) that DO NOT have an entry on the right side (sales_items).
Your problem can be fixed by using joins.
Read the following article about SQL-Joins and think about your problem -> you will be able to fix it ;)
The IN-clause is not the best solution, because some databases have limits on the number of arguments contained in it.
what you really wanted here is:
SELECT DISTINCT sale_id
FROM phppos_sales_items_taxes
WHERE sale_id NOT IN
(SELECT sale_id FROM phppos_sales_items)
WHERE field NOT IN (SELECT field FROM anothertable WHERE ...) is a perfectly fine query construct.
Your original query:
SELECT DISTINCT sale_id
FROM phppos_sales_items_taxes
WHERE item_id NOT IN
(SELECT item_id FROM phppos_sales_items WHERE sale_id = phppos_sales_items_taxes.sale_id)
Here you are pulling all the item_ids from the phppos_sales_items table where sale_id matches with taxes table, and removing those item_ids from the final result.
You can do also get same results in couple other ways, which may be easy to understand.
Use IN query with multiple columns:
select distinct sales_id
from sales_item_taxes
where (sale_id, item_id) not in (select sale_id, item_id from phppos_sales_items)
-- This form of query is easy to read and understand. Performance may not be good for large tables.
Exists / not exists format:
select distinct sales_id
from sales_item_taxes t1
where not exists (select '1' from phppos_sales_items t2
where t2.sale_id = t1.sale_id
and t2.item_id = t1.item_id
)
I would have also suggested the same solution as 'bwperrin' did - not sure why you didn't get any output by running the query. If your criteria is to filter on sale_id - that is the best solution. But looks like you are using (sale_id, item_id) as a way to identify sales record. Make sure your table structure makes sense.

how to get all enum field in a column side by side seperated by comma (,) in a mysql by query

In mysql i need to get enum fields side by side in a column when i run a query with group by , just like as follows.
There is table as like below
mysql> describe tabex;
+---------+----------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| personid| int(11) | YES | | NULL | |
| color | enum('red','blue','white') | YES | | NULL | |
+---------+----------------------------+------+-----+---------+----------------+
there are different shirts , the column personid describes the that person id and color indicates the color of his shirt..
the data in table is as follows
mysql> select * from tabex;
+----+----------+-------+
| id | personid | color |
+----+----------+-------+
| 1 | 1 | red |
| 2 | 1 | white |
| 3 | 2 | blue |
| 4 | 2 | red |
+----+----------+-------+
4 rows in set (0.00 sec)
when i ran a query i am getting results like this
mysql> select personid , color from tabex group by personid;
+----------+-------+
| personid | color |
+----------+-------+
| 1 | red |
| 2 | blue |
+----------+-------+
but i want the result like below
+----------+-------------+
|personid | color |
+----------+-------------+
|1 | red,white |
|2 | blue,red |
| | |
+----------+-------------+
how can i get the result as above by using group by and aggregation (if any for enum).
that is here i want to get the result for enum fields as like we will get by using count or sum functions and group by .
The GROUP_CONCAT() aggregate function does what you want:
SELECT personid, GROUP_CONCAT(color) colors
FROM tabex
GROUP BY personid
This works with any kind of field, not just ENUM.

mysql column count doesn't match value count (redux): yes it does. or does it?

Is MySQL giving me grief because the nested SELECT in the insert statement uses the COUNT(*) function instead of selecting an actual column? So, what's the workaround?
Here's the story:
mysql> explain test;
+----------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------------------+------+-----+---------+-------+
| language | varchar(50) | YES | | NULL | |
| count | smallint(5) unsigned | YES | | NULL | |
+----------+----------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> SELECT languages.name, COUNT(*) AS `total` FROM languages JOIN events ON languages.id = events.language_id GROUP BY name HAVING total > 250 ORDER BY total DESC;
+-----------+-------+
| name | total |
+-----------+-------+
| Spanish | 60079 |
| Foochow | 2838 |
| Mandarin | 2396 |
| Russian | 1675 |
| Arabic | 1410 |
| Cantonese | 1358 |
| Korean | 736 |
| French | 531 |
| Punjabi | 426 |
| Urdu | 408 |
| Hebrew | 276 |
| Pashto | 255 |
+-----------+-------+
12 rows in set (0.00 sec)
mysql> INSERT INTO test (`language`,`count`) VALUES ((SELECT languages.`name`, COUNT(*) AS `total` FROM languages JOIN events ON languages.id = events.language_id GROUP BY name HAVING total > 250 ORDER BY total DESC));
ERROR 1136 (21S01): Column count doesn't match value count at row 1
thanks.
MySQL doesn't support this sort of multiple-column-returning subquery, so the error message you're seeing is because the VALUES clause only contains one subquery, which is perforce (in a sense) only one column.
To fix it, you can skip the VALUES syntax, and just write:
INSERT
INTO test (`language`,`count`)
SELECT languages.`name`, COUNT(*) AS `total`
FROM languages
JOIN events
ON languages.id = events.language_id
GROUP
BY name
HAVING total > 250
ORDER
BY total DESC
;
(See ยง13.2.5.1 "INSERT ... SELECT Syntax" in the MySQL 5.6 Reference Manual.)
INSERT INTO test (`language`,`count`)
should be
INSERT INTO test (language,count)