How to fetch values with a MySQL query? - sql

I want to fetch all the records of First_Name, LastName, First Name Last Name in a mysql Query.
For example,
mytable looks like this:
rec Id First Name Last Name
1 Gnaniyar Zubair
2 Frankyn Albert
3 John Mathew
4 Suhail Ahmed
Output should be like this:
Gnaniyar Zubair, Frankyn Albert, John Mathew, Suhail Ahmed
Give me the SQL.

If this must the done in the query, you can use GROUP_CONCAT, but unless you're grouping by something it's a pretty silly query and the concatenation should really be done on the client.
SELECT GROUP_CONCAT(FirstName + ' ' + LastName
ORDER BY FirstName, LastName
SEPARATOR ', ') AS Names
FROM People;

It is not a matter of getting one row with all the records, but a matter of representation of data. Therefore, I suggest to take a simple SELECT query, take the records you need, then arrange them in the view layer as you like.
On the other hand, why do you need to solve this record concatenation at SQL level and not on view level?

If you wanted to get them in just one row, you're probably not using your database properly.
If you just want to join together the first and last names, that's easy:
SELECT CONCAT(`First Name`, ' ', `Last Name`) FROM mytable

Related

Search functionality for multiple fields using sql

I have a table that holds user data. It looks something like this:
ID Name Surname Age
1 Alice Moore 23
2 David Moore 45
If working with only one field, lets say Name, which I have to use for my search key then I could simply do something like this:
Select * from Users where Name Like '% Al %'
ORDER BY DIFFERENCE(Name , 'Al') desc;
and get the data for user 1.
If I want the search operation to take into account other fields too, lets say Surname, I am not sure how to proceed.
How would order by know what column to use in the end so I can return the list based on relevance.
Before anything I'd like to say that I'm not sure how advisable it would be following my solution below in tables with a considerable amount of data. It's simply something I came up that I think should work for your case.
First try
What you could do is order by the minimum difference of all columns of interest in each row.
SELECT FirstName,
LastName,
(SELECT MIN(v)
FROM (VALUES (DIFFERENCE(FirstName , 'Al')),
(DIFFERENCE(LastName , 'Al'))) AS value(v)) as diff
FROM Users WHERE FirstName LIKE 'Al%' OR FirstName LIKE 'Al%'
ORDER BY diff DESC;
Try an interactive fiddle here.
Second try
Another option is ordering your result in a descending order of the difference of the concatenated string of all the rows of interest.
SELECT FirstName,
LastName
FROM Users
WHERE CONCAT (FirstName, LastName) LIKE 'Al%'
ORDER BY
DIFFERENCE(CONCAT (FirstName, LastName) , 'Al') DESC;
Try an interactive fiddle here.

Updating table where LIKE has several criteria

I have two tables in PostgreSQL (version 9.3). The first holds id, title and the second holds schdname. I'm trying to create a select statement that will retrieve id and title where the title contains the schdname from the other table. The id, title table can hold several thousand rows. I can do this fine if I use WHERE LIKE for an individual schdname example but there are 40 plus names so this is not practical.
My original query ran like this which I know doesn't work but would show what I'm trying to achieve.
SELECT
id,
title,
dname
FROM
mytable
WHERE
title LIKE (
SELECT
schdname
FROM
schedule
)
This produces an error of more than one row returned by the subquery used as an expresssion. So my question is can this be achieved another way?
Here is one way to do that:
SELECT id, title, dname FROM mutable
JOIN schedule ON mutable.title like '%' || schedule.schdname || '%'
Or a sligtly more readable way:
SELECT id, title, dname FROM mutable
JOIN schedule ON POSITION(schedule.schdname in mutable.title)<>0
Are you actually using a wildcard with like? You don't say so above. If not you can replace like with IN. If you do want to do a wildcard join I'd recommend taking a substring of the columns and comparing that e.g.
names
james
jack
janice
select substr(names,1,2) as names_abbr
from names_table where names_abbr = (select ...)

MySQL SELECT query string matching

Normally, when querying a database with SELECT, its common to want to find the records that match a given search string.
For example:
SELECT * FROM customers WHERE name LIKE '%Bob Smith%';
That query should give me all records where 'Bob Smith' appears anywhere in the name field.
What I'd like to do is the opposite.
Instead of finding all the records that have 'Bob Smith' in the name field, I want to find all the records where the name field is in 'Robert Bob Smith III, PhD.', a string argument to the query.
Just turn the LIKE around
SELECT * FROM customers
WHERE 'Robert Bob Smith III, PhD.' LIKE CONCAT('%',name,'%')
You can use regular expressions like this:
SELECT * FROM pet WHERE name REGEXP 'Bob|Smith';
Incorrect:
SELECT * FROM customers WHERE name LIKE '%Bob Smith%';
Instead:
select count(*)
from rearp.customers c
where c.name LIKE '%Bob smith.8%';
select count will just query (totals)
C will link the db.table to the names row you need this to index
LIKE should be obvs
8 will call all references in DB 8 or less (not really needed but i like neatness)

SQL: Sorting By Email Domain Name

What is the shortest and/or efficient SQL statement to sort a table with a column of email address by it's DOMAIN name fragment?
That's essentially ignoring whatever is before "#" in the email addresses and case-insensitive. Let's ignore the internationalized domain names for this one.
Target at: mySQL, MSSQL, Oracle
Sample data from TABLE1
id name email
------------------------------------------
1 John Doe johndoe#domain.com
2 Jane Doe janedoe#helloworld.com
3 Ali Baba ali#babaland.com
4 Foo Bar foo#worldof.bar.net
5 Tarrack Ocama me#am-no-president.org
Order By Email
SELECT * FROM TABLE1 ORDER BY EMAIL ASC
id name email
------------------------------------------
3 Ali Baba ali#babaland.com
4 Foo Bar foo#worldof.bar.net
2 Jane Doe janedoe#helloworld.com
1 John Doe johndoe#domain.com
5 Tarrack Ocama me#am-no-president.org
Order By Domain
SELECT * FROM TABLE1 ORDER BY ?????? ASC
id name email
------------------------------------------
5 Tarrack Ocama me#am-no-president.org
3 Ali Baba ali#babaland.com
1 John Doe johndoe#domain.com
2 Jane Doe janedoe#helloworld.com
4 Foo Bar foo#worldof.bar.net
EDIT:
I am not asking for a single SQL statement that will work on all 3 or more SQL engines. Any contribution are welcomed. :)
Try this
Query(For Sql Server):
select * from mytbl
order by SUBSTRING(email,(CHARINDEX('#',email)+1),1)
Query(For Oracle):
select * from mytbl
order by substr(email,INSTR(email,'#',1) + 1,1)
Query(for MySQL)
pygorex1 already answered
Output:
id name email
5 Tarrack Ocama me#am-no-president.org
3 Ali Baba ali#babaland.com
1 John Doe johndoe#domain.com
2 Jane Doe janedoe#helloworld.com
4 Foo Bar foo#worldof.bar.net
For MySQL:
select email, SUBSTRING_INDEX(email,'#',-1) AS domain from user order by domain desc;
For case-insensitive:
select user_id, username, email, LOWER(SUBSTRING_INDEX(email,'#',-1)) AS domain from user order by domain desc;
If you want this solution to scale at all, you should not be trying to extract sub-columns. Per-row functions are notoriously slow as the table gets bigger and bigger.
The right thing to do in this case is to move the cost of extraction from select (where it happens a lot) to insert/update where it happens less (in most normal databases). By incurring the cost only on insert and update, you greatly increase the overall efficiency of the database, since that's the only point in time where you need to do it (i.e., it's the only time when the data changes).
In order to achieve this, split the email address into two distinct columns in the table, email_user and email_domain). Then you can either split it in your application before insertion/update or use a trigger (or pre-computed columns if your DBMS supports it) in the database to do it automatically.
Then you sort on email_domain and, when you want the full email address, you use email_name|'#'|email_domain.
Alternatively, you can keep the full email column and use a trigger to duplicate just the domain part in email_domain, then you never need to worry about concatenating the columns to get the full email address.
It's perfectly acceptable to revert from 3NF for performance reasons provided you know what you're doing. In this case, the data in the two columns can't get out of sync simply because the triggers won't allow it. It's a good way to trade disk space (relatively cheap) for performance (we always want more of that).
And, if you're the sort that doesn't like reverting from 3NF at all, the email_name/email_domain solution will fix that.
This is also assuming you just want to handle email addresses of the form a#b - there are other valid email addresses but I can't recall seeing any of them in the wild for years.
For SQL Server, you could add a computed column to your table with extracts the domain into a separate field. If you persist that column into the table, you can use it like any other field and even put an index on it, to speed things up, if you query by domain name a lot:
ALTER TABLE Table1
ADD DomainName AS
SUBSTRING(email, CHARINDEX('#', email)+1, 500) PERSISTED
So now your table would have an additional column "DomainName" which contains anything after the "#" sign in your e-mail address.
Assuming you really must cater for MySQL, Oracle and MSSQL .. the most efficient way might be to store the account name and domain name in two separate fields. The you can do your ordering:
select id,name,email from table order by name
select id,name,email,account,domain from table order by email
select id,name,email,account,domain from table order by domain,account
as donnie points out, string manipulation functions are non standard .. that is why you will have to keep the data redundant!
I've added account and domain to the third query, since I seam to recall not all DBMSs will sort a query on a field that isn't in the selected fields.
This will work with Oracle:
select id,name,email,substr(email,instr(email,'#',1)+1) as domain
from table1
order by domain asc
For postgres the query is:
SELECT * FROM table
ORDER BY SUBSTRING(email,(position('#' in email) + 1),252)
The value 252 is the longest allowed domain (since, the max length of an email is 254 including the local part, the #, and the domain.
See this for more details: What is the maximum length of a valid email address?
You are going to have to use the text manipulation functions to parse out the domain. Then order by the new column.
MySQL, an intelligent combination of right() and instr()
SQL Server, right() and patindex()
Oracle, instr() and substr()
And, as said by someone else, if you have a decent to high record count, wrapping your email field in functions in you where clause will make it so the RDBMS can't use any index you might have on that column. So, you may want to consider creating a computed column which holds the domain.
If you have million records, I suggest you to create new column with domain name only.
My suggestion would be (for mysql):
SELECT
LOWER(email) AS email,
SUBSTRING_INDEX(email, '#', + 1) AS account,
REPLACE(SUBSTRING_INDEX(email, '#', -1), CONCAT('.',SUBSTRING_INDEX(email, '.', -1)),'') -- 2nd part of mail - tld.
AS domain,
CONCAT('.',SUBSTRING_INDEX(email, '.', -1)) AS tld
FROM
********
ORDER BY domain, email ASC;
And then just add a WHERE...
The original answer for SQL Server didn't work for me....
Here is a version for SQL Server...
select SUBSTRING(email,(CHARINDEX('#',email)+1),len(email)), count(*)
from table_name
group by SUBSTRING(email,(CHARINDEX('#',email)+1),len(email))
order by count(*) desc
work smarter not harder:
SELECT REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING(emails.email, POSITION('#' IN emails.email)+1)),'.',2)) FROM emails

how can i write a sql query that finds rows where one column is a substring of another column

I wish to find all rows in a table where one column is a substring of another column.
In other words, suppose I have a table (called people) with two columns: firstname and lastname, and I want to find all people like "rob robinowitz" and "jill bajillion".
Is there a way to do something like "select * from people where lastname like %firstname%"? (But something which actually works).
You were close
select * from people where lastname like '%' + firstname + '%'
Alternative way (may be even faster)
select * from people where charindex(firstname,lastname)>0
If you are using MySQL you could
SELECT * FROM people WHERE INSTR(lastname, firstname) <> 0