Update Column from Columns within same table using SQLite - sql

I’m trying to update an email address value from users first- and lastname within the same table.
Pattern for generated Mail: <Firstname>.<Lastname>#test.org
Example Table “Persons”:
Firstname Lastname email
Henley Figueroa none#none.com
Samina Morrison none#none.com
Dev Rowe none#none.com
Wished result for table “Persons”:
Firstname Lastname email
Henley Figueroa Henley.Figueroa#test.org
Samina Morrison Samina.Morrison#test.org
Dev Rowe Dev.Rowe#test.org
SQL Code
UPDATE Persons
SET
email = (SELECT FirstName || "." || LastName ||"#"||"test.org" FROM Persons)
Actual result for table “Persons”:
Firstname Lastname email
Henley Figueroa Henley.Figueroa#test.org
Samina Morrison Henley.Figueroa#test.org
Dev Rowe Henley.Figueroa#test.org
Only the first record of the returned result table is used over and over. Why?
If I ommit the SELECT:
UPDATE Persons
SET
email = FirstName || "." || LastName ||"#"||"test.org"
I get the expected result.
Referring to your answers, I'm extending my question with an example of two tables. One with only names, the second for mail addresses.
Table Persons:
ID*
Firstname
Lastname
1
Henley
Figueroa
2
Samina
Morrison
3
Dev
Rowe
Table Addresses:
ID*
email
1
wrong#wrong.ng
2
wrong#wrong,ng
3
wrong#wro.ng
UPDATE Addresses
SET email = (SELECT Firstname ||"."|| Lastname || "#test.org"
FROM Persons WHERE Persons.id = Addresses.id)
Demo
Here the UPDATE with SET and SELECT works (Every person gets a unique mail address). Shouldn’t I get the same problem here?
From the output of SELECT I see that I get again (as expected) three records.

You have the right syntax for your problem. So the question is why does this not do what you want?
UPDATE Persons
SET email = (SELECT FirstName || "." || LastName ||"#"||"test.org"
FROM Persons
);
In fact, this should produce an error in any SQL engine -- although SQLite can be a bit lax about such errors. Why? The SET is expecting a single value. This code has a subquery that returns three values.
Note: The SQL Fiddle does show that SQLite accepts this syntax. Argggh! You can switch this to Postgres to see the error. With some modifications, to the create code you could also see the same error (subquery returns more than one row) using SQL Server or Oracle or just about any database.
Apparently, SQLite is just arbitrarily choosing one of those values -- the one that it first encounters. And this is the same value for all three rows.
You already know that a subquery is not correct here. You have the correct code in your question.

From Subquery Expressions:
A SELECT statement enclosed in parentheses is a subquery. All types of
SELECT statement, including aggregate and compound SELECT queries
(queries with keywords like UNION or EXCEPT) are allowed as scalar
subqueries. The value of a subquery expression is the first row of
the result from the enclosed SELECT statement. The value of a
subquery expression is NULL if the enclosed SELECT statement returns
no rows.
So the value you get by the subquery is the first row of the rows returned.
Of course, you don't need the SELECT statement.
This is a simple UPDATE statement that involves only the values of the columns of the current row:
UPDATE Persons
SET email = FirstName || '.' || LastName || '#' || 'test.org'
See the demo.
Results:
Firstname
Lastname
email
Henley
Figueroa
Henley.Figueroa#test.org
Samina
Morrison
Samina.Morrison#test.org
Dev
Rowe
Dev.Rowe#test.org
For the 2nd query with the 2 tables:
Shouldn’t I get the same problem here?
No, because the subquery is a correlated subquery, which returns for each row in the table Addresses only 1 row (provided there are no duplicate ids in Persons), the row which matches the condition Persons.id = Addresses.id.
If there is no row that matches the condition then it will return NULL.

Related

Updating with a select one table

I want to update a column with a concatenation of other columns within the same table.
This is for customer names in a table. There are separate columns for "Title" i.e. Mr, Ms, Mrs etc, "FirstName", "MiddleName" and "LastName". I altered the table by adding a new "FullName" column, which I tried to fill with a concatenation of the former columns.
SET [SalesLT].[Customer].[FullName] = (SELECT
Title,
FirstName,
MiddleName,
LastName,
CONCAT(Title,' ',FirstName,' ',MiddleName,' ',LastName) as FullName
FROM [AdventureWorksLT2008R2].[SalesLT].[Customer])
WHERE FullName = NULL;
I'm getting this
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
Since you are updating a column value based on other columns in the same table, you not select them again.
UPDATE [SalesLT].[Customer]
SET [SalesLT].[Customer].[FullName] =
CONCAT(Title,' ',FirstName,' ',MiddleName,' ',LastName)
WHERE FullName is NULL;
Note: I did not change your where clause condition, neither concat function. In some databases you may need to do FullName is NULL instead of FullName = NULL. And in some databases, you may need to concat multiple values with ||.

Matching tuples in sql

I am trying to write a query that matches a tuple of columns from a list. So let's say I have list of first names and last names and I want to match the combination of first and last name of the same index from the database.
first_names = ["Joe", "Freddy", "Michael"]
last_names = ["Jason", "Kruger", "Myers"]
In this case I want query to return some other column for a record that has either name "Joe Jason", "Freddy Kruger" or "Michael Myers".
For me, the obvious way is to group by first and last name and use group concat then match against concatenated field. But I want to try to avoid that. Is there anyway matching by tuples can be done in SQL?
Some databases allow you to express this logic as:
where (firstname, lastname) in ( ('Joe', 'Jason'), ('Freddy', 'Kruger'), ('Michael, 'Myers') )
In all, you can express this using boolean logic:
where (firstname = 'Joe' and lastname = 'Jason') or
(firstname = 'Freddy' and lastname = 'Kruger') or
(firstname = 'Michael' and lastname = 'Myers')

SQL SERVER Query Select by FirstName, Lastname

My Products table has almost 10,000 records where i want the "artist" ( varchar ) column name to sort by Firstname and Lastname. In the where clause i am sending initial letter of either first name or lastname. This Query works for few records but not for all, its probably because of the pattern of the records ?
Here is my query
SELECT * FROM Products WHERE SUBSTRING(artist, 1, 1) Like 'C'
Doesnt return the records... the way i want it ...Few of the records of the table ( artist) column are below
Comtesse Mathilde duMonceau de Bergendael
Mulholland, S.J.
Cleminson
NULL
Samuel Jackson
Your LIKE clause is wrong. Also you should not be using LIKE at all here, as you're only filtering by one letter:
.... WHERE LEFT(artist, 1) = 'C'
EDIT LEFT is actually faster than SUBSTRING.
Also, you can not expect anything that's not starting with a C to be returned, as you're explicitly only asking for entries that start with a C.
I guess what you really need is the following:
.... WHERE LEFT(FirstName, 1) = 'C' OR LEFT(LastName, 1) = 'C' ORDER BY LastName, Firstname
If you only have the Artist column, things get complicated, as you actually do need to use LIKE, which makes things pretty slow
.... WHERE Artist LIKE `%C%`
returns any artist, the name of which contains a C anywhere in the name. This would also return these:
Clemens Test
Test Cutler
Arachnophobia
User this where clause
where left(artist, 1) = 'C'
or
where artist like 'C%'

SQL BETWEEN not working properly

I am using Microsoft SQL Server
I am trying to use the following sql command to get the records between First_Name "Nilsen" and "Ram"
select * from persons where First_Name between 'Nilsen' and 'Ram'
but i am getting the output as two records with first names "nilsen" and "ram"; not the records between these records.
In another command, i tried doing similar thing with Last names.
select * from persons where Last_Name between 'Johan' and 'Chandra'
this command shows just a blank persons table.
Please tell me its not working properly.
This query:
SELECT *
FROM persons
WHERE First_Name between 'Nilsen' and 'Ram'
will return all entries with First_Name alphabetically between Nilsen and Ram (like Oscar, Rachel or Norbert)
This query:
SELECT *
FROM persons
WHERE Last_Name between 'Johan' and 'Chandra'
will never return anything since Johan is greater than Chandra (i. e. goes later in alphabetical order).
Update:
Just a wild guess: if you want to match something like Nilsen Hermenegild J. P. Ram, Jr., you need to use this:
SELECT *
FROM persons
WHERE FirstName LIKE '%Nilsen%Ram%
This is how BETWEEN works, from MSDN
BETWEEN returns TRUE if the value of
test_expression is greater than or
equal to the value of begin_expression
and less than or equal to the value of
end_expression.
so
select * from persons where First_Name between 'Nilsen' and 'Ram'
should return records with first names 'Nilsen' and 'Ram', plus the records between.
Just guessing, try this:
select * from persons where lower(First_Name) between 'nilsen' and 'ram'

How to fetch values with a MySQL query?

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