MySQL order by two columns in or-clause - mysql

I have a table in MySQL with some data like below:
id name first_name
===============================
1 hello
2 many
3 alive
4 persons
How can I make the result look like this
id name first_name
===============================
3 alive
1 hello
2 many
4 persons
So, the sorting should be alphabetic on name and/or first_name?

The following query would do the work.
SELECT *
FROM nameTable
ORDER BY IFNULL(name,first_name)
OR
SELECT *
FROM nameTable
ORDER BY coalesce(name,first_name)
N:B: If you cannot access SQL FIDDLE.
CREATE TABLE `nameTable` (
`ID` int(11) NOT NULL AUTO_INCREMENT ,
`name` varchar(50) CHARACTER SET latin1 COLLATE latin1_general_ci NULL DEFAULT NULL ,
`first_name` varchar(50) CHARACTER SET latin1 COLLATE latin1_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`ID`)
);
INSERT INTO `nametable` VALUES ('1', 'hello', null);
INSERT INTO `nametable` VALUES ('2', null, 'many');
INSERT INTO `nametable` VALUES ('3', null, 'alive');
INSERT INTO `nametable` VALUES ('4', 'persons', null);
Note:
The main difference between the two is that IFNULL function takes two arguments and returns the first one if it's not NULL or the second if the first one is NULL.
COALESCE function can take two or more parameters and returns the first non-NULL parameter, or NULL if all parameters are null.

I found the solution, the order by should look like
order by coalesce(name,first_name)

Create a sortby column which is a concatenation of the two other columns.
SELECT id, `name`, first_name, CONCAT(IFNULL(`name`,''),IFNULL(first_name,'')) AS sortby
FROM
table1
ORDER BY sortby

use this
SELECT * FROM A ORDER BY CONCAT(name,first_name) ASC

Related

Return all data from left table, even if where clause is not attended

I have a seller_commissions table, where are related with two other tables: products and sellers (users)
I need to make a painel, where admin can update seller commissions for each product.
Products will be created over time, so I don't want to insert data in seller_commissions table when this occurs, because I would need to do this multiples times. So, my solution was:
get all products data for user's update. If seller_commissions are null for specific product, this means the target seller never has your commission updated. In other words, all sellers have commission = 0 in first moment.
I try the following queries:
-- This is the result what I want, but filtering by seller_id, but, unfortannaly this return all products for each seller (I want to specify the seller_id)
select fpp.name as product_name,
fsc.seller_id,
fsc.commission
from fp_products as fpp
left join fp_sellers_commissions as fsc
on fsc.product_id = fpp.id
left join fp_users as fpu
on fpu.id = fsc.seller_id;
-- If I use 'where' clause, not all products are returned, because seller_id is none
select fpp.name as product_name,
fsc.seller_id,
fsc.commission
from fp_products as fpp
left join fp_sellers_commissions as fsc
on fsc.product_id = fpp.id
left join fp_users as fpu
on fpu.id = fsc.seller_id
where seller_id = 1;
result for first query:
result for second query:
expected results:
product_name
seller_id
commission
shirt
1
250
shoes
null
0
black shirt
null
0
In first query, is something similiar with what I want. Get all products and seller_commission, but I want this for a specific seller, but when I try to use WHERE clause, I don't get all products, because seller_id can be null. I try some variations of these queries, but can't get the expected result :/. Appreciate any help.
to build the schema, use:
-- Create schema
CREATE TABLE `fp_sellers_commissions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commission` float NOT NULL DEFAULT '0',
`product_id` int(11) NOT NULL,
`seller_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `fp_products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) CHARACTER SET latin1 NOT NULL,
`createdAt` datetime DEFAULT CURRENT_TIMESTAMP,
`disabled` tinyint(4) DEFAULT '0',
PRIMARY KEY (`id`)
);
CREATE TABLE `fp_users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) CHARACTER SET latin1 NOT NULL,
`surname` varchar(32) CHARACTER SET latin1 NOT NULL,
PRIMARY KEY (`id`)
);
-- Inserting data:
INSERT INTO `fp_products`
(`id`, `name`, `createdAt`, `disabled`)
VALUES
(1, 'shirt', '00:00:00', 0),
(2, 'shoes', '00:00:00', 0),
(3, 'black shirt', '00:00:00', 0);
INSERT INTO `fp_users`
(`id`,
`name`,
`surname`)
VALUES
(1, 'bilbo', 'aaa'),
(2, 'frodo', 'aaa');
INSERT INTO `fp_sellers_commissions`
(`id`, `commission`, `product_id`, `seller_id`)
VALUES
(1, 100, 1, 1),
(2, 500, 1, 2);
Or you can acess SQL FIDDLE: http://sqlfiddle.com/#!9/d6559f/5
I'm not sure why the expected result should be with a commission of "250" for the seller "1", but I think I got what you are searching for. If you want to filter the seller's commission and still display the other products with nulls, you could put the filter condition directly on the left join, kinda like the following.
select fpp.name as product_name,
fsc.seller_id,
fsc.commission
from fp_products as fpp
left join fp_sellers_commissions as fsc
on fsc.product_id = fpp.id and fsc.seller_id = 1
left join fp_users as fpu
on fpu.id = fsc.seller_id;
What happens here, is that the filtering condition is applied at the moment you do the left join, so if it does not match, since it is a "left" join, the results will still be returned with nulls. If you put it in the "where" clause, it will be applied after the join is applied, and it will filter out the results that do not match.
My suggestion is
select fpp.name as product_name,
fsc.seller_id,
SUM(ifnull(fsc.commission, 0)) as commission
from fp_products as fpp
left join fp_sellers_commissions as fsc
on fpp.id = fsc.product_id and fsc.seller_id = 1
group by fpp.name, fsc.seller_id
order by fsc.seller_id desc;
with this must be getting the result you need. Note: I added a group summing to commissions, but if not is the goal, just remove the group by and the sum function.
Hoping this can help you.

How to use properly IN clause getting the value from another column in MySQL?

In one table I have a list of cities and in another a list of clients. On clients I have a varchar column identifiend a list of cities separated by commas (ex: "2,3,4").
When I tried to list the cities of a client it is shown just the first city of the list.
It seem that is adding some quotation marks on the value like:
select GROUP_CONCAT(city.name)
from city where city.id_city in ('2,3,4')
¿How can avoid this situacion?
https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=a70c667e820c3208053b324075b0462c
CREATE TABLE `city` (
`id_city` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id_city`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `client` (
`id_client` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
`cities` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id_client`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO city (id_city,name) VALUES ('1','New York');
INSERT INTO city (id_city,name) VALUES ('2','Boston');
INSERT INTO city (id_city,name) VALUES ('3','San Diego');
INSERT INTO city (id_city,name) VALUES ('4','Seatle');
INSERT INTO city (id_city,name) VALUES ('5','Chicago');
INSERT INTO client (id_client,name,cities) VALUES ('1','Client_1','2,3,4');
select client.id_client, client.name, (select GROUP_CONCAT(city.name)
from city where city.id_city in (client.cities)) as cities from client;
You cannot directly pass the list to your queries. You need to change your code to -
SELECT client.id_client,
client.name,
(SELECT GROUP_CONCAT(city.name)
FROM city
WHERE FIND_IN_SET(city.id_city, client.cities) <> 0) AS cities
FROM client;
DB Fiddle.
Though this solves your purpose, I think you must consider visiting this link which clearly says that storing the comma-separated values is really a very bad idea.

MySQL: Use substring to derive data from two different columns

I have the following table:
CREATE TABLE `vendor_contacts` (
`vendor_id` int(11) NOT NULL,
`last_name` varchar(50) NOT NULL,
`first_name` varchar(50) NOT NULL,
`name_initials` varchar(45) NOT NULL,
PRIMARY KEY (`vendor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
With the following insert statement:
INSERT INTO `vendor_contacts`
VALUES (5,'Davison','Michelle',''),
(12,'Mayteh','Kendall',''),
(17,'Onandonga','Bruce',''),
(44,'Antavius','Anthony',''),
(76,'Bradlee','Danny',''),
(94,'Suscipe','Reynaldo',''),
(101,'O\'Sullivan','Geraldine',''),
(123,'Bucket','Charles','');
I would like to run a query that extracts the first letter from the first name and last name columns.
SELECT vendor_id, last_name, first_name, substring(first_name, 1, 1) AS initials
FROM vendor_contacts;
The following guide http://www.w3resource.com/mysql/string-functions/mysql-substring-function.php, only shows how to work with one column.
You pull them separately and combine them using concat():
SELECT vendor_id, last_name, first_name,
CONCAT(LEFT(first_name, 1), LEFT(last_name, 1)) as initials
FROM vendor_contacts;

MySQL. Error code 1136

i´m trying to insert some values in mysql but i get error code 1136, i verified and one of the values is auto-increment so i don't have to enter that one and the rest give a total of 18 which are exactly the total values i'm writting, could somebody help me?
This is the table im using:
FIELD TYPE NULL KEY DEFAULT EXTRA
id_display_detail int(11) NO PRI auto_increment
amount double NO
amount_lc double NO
exchange double NO
company varchar(10) NO
date datetime NO
description varchar(100) NO
document_number varchar(20) NO
document_type varchar(2) NO
posting_key varchar(3) NO
special_gl varchar(1) NO
status int(11) NO
voucher_number varchar(40) NO
year int(11) NO MUL
id_currency int(11) NO MUL
id_employee int(11) NO MUL
credit bit(1) YES
card_type varchar(45) NO
line_item int(11) YES
And this is my code:
INSERT INTO display_detail VALUES (300,300,0,'2001','2016-04-11',
'Downpayment ZM00080621','2000010802','ZP','29','R',0,
'GCCTEA 8062130',2016,1,1561,0,NULL,1);
Am i missing something?
and one of the values is auto-increment so i don't have to enter that one
That doesn't change the fact that the number of values in your VALUES clause has to match the number of columns.
You need to either specify NULL as the value for the auto_increment column - or specify a column list after INSERT first.
You missing the column name
(Because the id is automatic the values you provided don't math the number of column so must declare the column name)
INSERT INTO display_detail ( amount,
amount_lc ,
exchange ,
company ,
date ,
description ,
document_number,
document_type ,
posting_key ,
special_gl ,
status ,
voucher_number ,
year ,
id_currency ,
id_employee ,
credit ,
card_type ,
line_item ) VALUES (300,300,0,'2001','2016-04-11',
'Downpayment ZM00080621','2000010802','ZP','29','R',0,
'GCCTEA 8062130',2016,1,1561,0,NULL,1);
It appears that you aren't listing the columns in your INSERT statement. A MySQL query typically looks like this:
INSERT INTO table
(column1, column2, ... )
VALUES
(expression1, expression2, ... ),
(expression1, expression2, ... ),
...;
(Taken from: http://www.techonthenet.com/mysql/insert.php)
The final query would be something like this:
INSERT INTO display_detail
(amount, amount_lc, exchange, company, date, description,
document_number, document_type, posting_key,special_gl,status,voucher_number,year,
id_currency, id_employee, credit, card_type, line_item)
VALUES (300,300,0,'2001','2016-04-11',
'Downpayment ZM00080621','2000010802','ZP','29','R',0,
'GCCTEA 8062130',2016,1,1561,0,NULL,1);

How to use INSERT ... SELECT with a particular column auto-incrementing, starting at 1?

I am using INSERT ... SELECT to insert a data from specific columns from specific rows from a view into a table. Here's the target table:
CREATE TABLE IF NOT EXISTS `queue` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`customerId` int(11) NOT NULL,
`productId` int(11) NOT NULL,
`priority` int(11) NOT NULL,
PRIMARY KEY (`ID`),
KEY `customerId` (`customerId`),
KEY `productId` (`productId`),
KEY `priority` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
The INSERT ... SELECT SQL I have works, but I would like to improve it if possible, as follows: I would like the inserted rows to start with 1 in the priority column, and each subsequent row to increment the priority value by 1. So, if three rows were inserted, the first would be priority 1, the second 2, and the third 3.
A exception to the "start at 1" rule: if there are existing rows in the target table for the specified customer, I would like the inserted rows to start with MAX(priority)+1 for that customer.
I thought I could use a subquery, but here's the problem: sometimes the subquery returns NULL (when there are no records in the queue table for the specified customer), which breaks the insert, as the priority column does not allow nulls.
I tried to CAST the column to an integer, but that still gave me NULL back when there are no records with that customer ID in the table.
I've hardcoded the customer ID in this example, but naturally in my application that would be an input parameter.
INSERT INTO `queue`
(
`customerId`,
`productId`,
`priority`,
`status`,
`orderId`)
SELECT
123, -- This is the customer ID
`PRODUCT_NO`,
(SELECT (MAX(`priority`)+1) FROM `queue` WHERE `customerId` = 123),
'queued',
null
FROM
`queue_eligible_products_view`
Is there a way to do this in one SQL statement, or a small number of SQL statements, i.e., less than SQL statement per row?
I do not think I can set the priority column to auto_increment, as this column is not necessarily unique, and the auto_increment attribute is used to generate a unique identity for new rows.
As Barmar mentions in the comments : use IFNULL to handle your sub query returning null. Hence:
INSERT INTO `queue`
(
`customerId`,
`productId`,
`priority`,
`status`,
`orderId`)
SELECT
123, -- This is the customer ID
`PRODUCT_NO`,
IFNULL((SELECT (MAX(`priority`)+1) FROM `queue` WHERE `customerId` = 123),1),
'queued',
null
FROM
`queue_eligible_products_view`
Here's how to do the incrementing:
INSERT INTO queue (customerId, productId, priority, status, orderId)
SELECT 123, product_no, #priority := #priority + 1, 'queued', null
FROM queue_eligible_products_view
JOIN (SELECT #priority := IFNULL(MAX(priority), 0)
FROM queue
WHERE customerId = 123) var