Updating with a select one table - sql

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 ||.

Related

inserting multiples values in one column

I have a question about SQL. I have created a table in SQL with only one column containing the name of two people (say John and Matt). Later I added a new column into the table with ALTER TABLE. This column will contain the surname of these people.
My question is, in case mmy table contained several people already is there a command to enter the surnames for all the people at once rather than writing one command for each person as in:
INSERT INTO table (Surname) VALUE (John's surname) and
INSERT INTO table (Surname) VALUE (Matt's surname) ?
Thanks in advance
P.D.
I tried something like:
UPDATE foo set Surname=("Parker","Walker") where Name =("John","Matt") but does not work
You want an update. Something like this:
update t
set surname = 'John'' surname'
where firstname = 'John';
You can do this separately for each name. Or use a case expression for multiple ones:
UPDATE foo
SET Surname = (CASE WHEN Name = 'John' THEN 'Parker'
WHEN Name = 'Matt' THEN 'Walker'
END)
WHERE Name IN ('John', 'Matt');

How to execute a select with a WHERE using a not-always-existing column

Simple example: I have some (nearly) identical tables with personal data (age, name, weight, ...)
Now I have a simple, but long SELECT to find missing data:
Select ID
from personal_data_a
where
born is null
or age < 1
or weight > 500
or (name is 'John' and surname is 'Doe')
Now the problem is:
I have some personal_data tables where the column "surname" does not exit, but I want to use the same SQL-statement for all of them. So I have to check (inside the WHERE clause) that the last OR-condition is only used "IF the column surname exists".
Can it be done in a simple way?
You should have all people in the same table.
If you can't do that for some reason, consider creating a view. Something like this:
CREATE OR REPLACE VIEW v_personal_data
AS
SELECT id,
born,
name,
surname,
age,
weight
FROM personal_data_a
UNION ALL
SELECT id,
born,
name,
NULL AS surname, --> this table doesn't contain surname
age,
weight
FROM personal_data_b;
and then
SELECT id
FROM v_personal_data
WHERE born IS NULL
OR age < 1
OR ( name = 'John'
AND ( surname = 'Doe'
OR surname IS NULL))
Can it be done in a simple way?
No, SQL statements work with static columns and the statements will raise an exception if you try to refer to a column that does not exist.
You will either:
need to have a different query for tables with the surname column and those without;
have to check in the data dictionary whether the table has the column or not and then use dynamic SQL to build your query; or
to build a VIEW of the tables which do not have that column and add the column to the view (or add a GENERATED surname column with a NULL value to the tables that are missing it) and use that instead.
While dynamic predicates are usually best handled by the application or by custom PL/SQL objects that use dynamic SQL, you can solve this problem with a single SQL statement using DBMS_XMLGEN, XMLTABLE, and the data dictionary. The following code is not what I would call "simple", but it is simple in the sense that it does not require any schema changes.
--Get the ID column from a PERSONAL table.
--
--#4: Get the IDs from the XMLType.
select id
from
(
--#3: Convert the XML to an XMLType.
select xmltype(personal_xml) personal_xmltype
from
(
--#2: Convert the SQL to XML.
select dbms_xmlgen.getxml(v_sql) personal_xml
from
(
--#1: Use data dictionary to create SQL statement that may or may not include
-- the surname predicate.
select max(replace(replace(
q'[
Select ID
from #TABLE_NAME#
where
born is null
or age < 1
or weight > 500
or (name = 'John' #OPTIONAL_SURNAME_PREDICATE#)
]'
, '#TABLE_NAME#', table_name)
, '#OPTIONAL_SURNAME_PREDICATE#', case when column_name = 'SURNAME' then
'and surname = ''Doe''' else null end)) v_sql
from all_tab_columns
--Change this literal to the desired table.
where table_name = 'PERSONAL_DATA_A'
)
)
where personal_xml is not null
)
cross join xmltable
(
'/ROWSET/ROW'
passing personal_xmltype
columns
id number path 'ID'
);
See this db<>fiddle for a runnable example.

Update Column from Columns within same table using SQLite

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.

selecting with a column being one of two possible values

I have a table called "people" with a column named "name". I would like to select all rows where the name is "bob" or "john". I have tried the following and many variants of it, none of which work. How can I do this correctly?
select * from people where name is bob or john;
Thanks
To compare a column with a value you need to use = not IS
select *
from people
where name = 'bob'
or name = 'john';
Alternatively you can use the IN operator.
select *
from people
where name IN ('bob','john');
Note that string comparison is case-sensitive in SQL. So the above will not return rows where the name is Bob or John

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')