SQL Server STRING_SPLIT() - sql

I'm trying to use this function on a column but it seems that that is not allowed:
If I use
SELECT *
FROM STRING_SPLIT('John,Jeremy,Jack', ',')
I get the values 'John', 'Jeremy and 'Jack'
Whilst if I use:
SELECT *
FROM STRING_SPLIT(Obs, ' ')
(Obs is text)
or
SELECT *
FROM STRING_SPLIT(appointments notes, ' ')
I get the error message:
Argument data type void type is invalid for argument 1 of string_split function
I even tried:
SELECT *
FROM STRING_SPLIT(select obs from log, '-')
which results in this error:
Incorrect syntax near the keyword 'select'.
Msg 102, Level 15, State 1, Line 6
Incorrect syntax near '-'
How can I solve this issue?

When you are using string_split() on a column of a table you can try it with cross apply.
Here goes your query:
select value from
log cross apply STRING_SPLIT(obs,',')
DB-Fiddle
your query:
create table log(Obs varchar(500));
insert into log values('ohn,Jeremy,Jack');
Your query:
select value from
log cross apply STRING_SPLIT(obs,',')
Output:
value
ohn
Jeremy
Jack
example:
CREATE TABLE contacts (
id INT PRIMARY KEY IDENTITY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
phones VARCHAR(500)
);
INSERT INTO
contacts(first_name, last_name, phones)
VALUES
('John','Doe','(408)-123-3456,(408)-123-3457'),
('Jane','Doe','(408)-987-4321,(408)-987-4322,(408)-987-4323');
Query:
SELECT
first_name,
last_name,
value phone
FROM
contacts
CROSS APPLY STRING_SPLIT(phones, ',');
Output:
first_name
last_name
phone
John
Doe
(408)-123-3456
John
Doe
(408)-123-3457
Jane
Doe
(408)-987-4321
Jane
Doe
(408)-987-4322
Jane
Doe
(408)-987-4323
db<fiddle here

Thank you all for the help, I've tried your suggestions but keep getting the same errors.
Here is a 2 record sample from the log column:
Obs
ID:786988|Patient_ID:320165|Staff_ID:PF|Date:05/06/2021 13:00:24|DiaryTemplates_ID:244799|Notes:Relatório 786988|Access:1|EventID:5|Status:4|Staff_ID_Writer:PES|Staff_ID_Signature:0|StatusReason:|StatusObs:|DateReceived:05/06/2021 13:00:24|NameReceived:|CountPrints:0|Staff_ID_Auxiliar:PES|PatientEpisode_ID:664831|
ID:872474|Patient_ID:340246|Staff_ID:PFI|AppointmentDate:29/05/2021 09:33:21|Convencao:XCD_ttt_NE_C2|NBenef:3X34977|NRequisicao:4SFR09995393153409|NAutorization:|Treatment_ID:6898|TreatmentCode:743.9|TotalValue:75,34|PatientValue:0,00|ConvencaoValue:75,34|StaffValue:0,00|FactConvencao:True|FactConvencaoDate:31/05/2021 19:14:53|FactStaff:False|FactStaffGuID:|PatientValueDiscount:0,00|Recibo:True|ReciboGuID:|FactConvencaoClinic_ID:HJUSD2|Piece:|ClinicsLocations_ID:1|FactConvencaoYearMonth:202105|FactConvencaoSequencial:31|FactConvencaoLote:155|FactConvencaoStaff_ID:TRI|Quantity:1|FactConvencaoLoteType:M|RequesterCode_Medico:M2XD33|RequesterCode_CentroSaude:XCD202|PatientDiary_ID:F45724|Appointment_ID:793049|DataExecucao:29/05/2021 09:30:00|DataEntrega:04/06/2021 00:00:00|PatientEpisode_ID:664807|ToExecute:True|Position:1|FactConvencaoNDevolucao:|FactConvencaoCanDefact:|NRequisicaoDate:|DataFacturacao:29/05/2021 09:33:21|ClinicalReportsDestinations_ID:|ClinicalReportsDestinations_ByWho:|ClinicalReportsDestinations_Date:|ClinicalReportsDestinations_DateDelivery:|TypeOrigem:|SPMS_IdMcdt:|
Each of the strings between '|' and ':' is a column name for another table, with its value after the ':'. The data type is 'text'.
I need to split those values into separate columns to update the other table.
Thanks.

Related

Implicit outer apply in SQL

thank you in advance for any assistance you can provide.
I am having to work in Oracle SQL and one issue I'm coming across is how to use applies in SQL. Specifically, hoping someone can help me write the code below to work in SQL. It's not a great example but I'm trying to figure out if there is a good way to:
do implicit applies, referencing columns from the "from" clause table, so they can be used in future applies/joins in the same query without having to do multiple temp tables, CTEs, or inner queries.
same question using top 1 in outer applies
Example:
--Drop Table #Users Drop Table #UsersLoginAttempts
Create table #Users(Username varchar(10), Password1 int)
Create Table #UsersLoginAttempts (Username varchar(10), Password1 int, AttemptDate date)
insert into #Users Values(' MAllen',123), ('SEllis ',124), ('MChen ',126)
insert into #UsersLoginAttempts Values
('MAllen ',123, '20221001'), (' SEllis ',124, '20221001')
, (' MChen ',126, '20221001'), ('MAllen ',126, '20221008')
, (' SEllis ',123, '20221008'), (' MChen',128, '20221008')
Select t.*, u.*
from #Users t
outer apply ( select ltrim(rtrim(t.username)) as UserNameTrim) unt
Outer apply ( select top 1 * from #UsersLoginAttempts ula
where ltrim(rtrim(ula.UserName)) = unt.UserNameTrim
order by ula.AttemptDate desc) u
You do not need the first OUTER APPLY (and would need to add FROM DUAL if you did include it as, in Oracle, all queries must include a table name) and TOP is not supported syntax, you can use FETCH FIRST ROW ONLY instead:
Select t.*,
u.*
from Users u
Outer apply (
select *
from UsersLoginAttempts ula
where TRIM(ula.UserName) = TRIM(u.UserName)
order by ula.AttemptDate desc
FETCH FIRST ROW ONLY
) t
Which, for your sample data:
*Note:
Do not use # as the first character of an identifier (otherwise you will need to use quoted identifiers throughout your code).
Your INSERT syntax is not valid for Oracle; use INSERT ALL ... OR INSERT INTO ... SELECT if you want to insert multiple rows.
Use VARCHAR2 and not VARCHAR.
'20221001' is not a date; it is a string literal. If you want to insert a date then either use TO_DATE, with a format model, to explicitly convert it or use a date literal DATE '2022-10-01'.
Create table Users (
Username varchar2(10),
Password1 int
)
Create Table UsersLoginAttempts (
Username varchar2(10),
Password1 int,
AttemptDate date
)
insert into Users (username, password1)
SELECT ' MAllen', 123 FROM DUAL UNION ALL
SELECT 'SEllis ', 124 FROM DUAL UNION ALL
SELECT 'MChen ', 126 FROM DUAL;
insert into UsersLoginAttempts (username, password1, attemptdate)
SELECT 'MAllen ', 123, DATE '2022-10-01' FROM DUAL UNION ALL
SELECT ' SEllis ', 124, DATE '2022-10-01' FROM DUAL UNION ALL
SELECT ' MChen ', 126, DATE '2022-10-01' FROM DUAL UNION ALL
SELECT 'MAllen ', 126, DATE '2022-10-08' FROM DUAL UNION ALL
SELECT ' SEllis ', 123, DATE '2022-10-08' FROM DUAL UNION ALL
SELECT ' MChen', 128, DATE '2022-10-08' FROM DUAL;
Outputs:
USERNAME
PASSWORD1
ATTEMPTDATE
USERNAME
PASSWORD1
MAllen
126
08-OCT-22
 MAllen
123
 SEllis
123
08-OCT-22
SEllis
124
 MChen
128
08-OCT-22
MChen
126
Note: this is not PL/SQL, which is Oracle Procedural Language (similar to T-SQL for SQL Server), it is just Oracle's dialect of SQL.
fiddle

select first_name,length(trim(FIRST_NAME)) as lengthOfName_without_space from employees;

i have first name as 'jose manuel' in my database- its total character length is 11 (combining space)
when i run the above query it is showing me output as 11.
but i need output without space i mean after trimming space ie., 10.
how do i do that in sql.
I'm looking through the comments, and The Impaler is correct.
In this circumstance, using Replace would help you a lot.
I've included testing data into a temporary table.
You can just use the select part without the stuff above that, just change the from part.
Declare #TestData TABLE
(
FIRST_NAME varchar(24)
);
INSERT INTO #TestData (FIRST_NAME) select 'jose manuel'
INSERT INTO #TestData (FIRST_NAME) select 'bob chris'
INSERT INTO #TestData (FIRST_NAME) select 'steven'
select t1.FIRST_NAME,
len(t1.FIRST_NAME) as 'Original_Length',
len( replace(t1.FIRST_NAME, ' ', '') ) as 'New_Length'
from #TestData as t1
The result of this will give you:
FIRST_NAME
Original_length
New_length
jose manuel
11
10
bob chris
9
8
steven
6
6

I am getting an error while using an insert query in sql create table #vr_test (x varchar not null ) insert into #vr_test select 'JAMES'

I am getting an error while using an insert query in sql
create table #vr_test (x varchar not null ) ;
insert into #vr_test
select 'JAMES' ;
error
Msg 8152, Level 16, State 14, Line 24
String or binary data would be truncated.
The statement has been terminated.
could you please help .. thanks in advance
Presumably, you are using SQL Server. You should always include a length when using varchar(). The default length varies by context:
create table #vr_test (
x varchar(255) not null
) ;
insert into #vr_test(x)
select 'JAMES' ;
The default for a type definition is 1 character. That is why you are getting an error.
Declare the VARCHAR field with the number of characters:
create table #vr_test (x varchar(100) not null )
insert into #vr_test select 'JAMES'
If you are running in oracle, then following should work:
create table
"#vr_test"
(x varchar2(50));
insert into "#vr_test"
select 'JAMES' from dual;
select * from "#vr_test";

SQL Substring Functions

I have a column named full name. I want to split them into two columns, first name and last name.
I am having a trouble with a persons with two first names. If the first name encounters a space it was considered last name.
I want this:
Full name : John Michael Smith
Firstname: John Michael
Lastname: Smith
However, I am getting:
Firstname: John
Lastname: Michael Smith
Try:
declare #n varchar(max) = 'John Michael Smith'
select REVERSE(SUBSTRING(REVERSE(#n), CHARINDEX(' ', REVERSE(#n)), 100)) FirstName
Check the below link:
SQL SERVER – Reverse String Word By Word – Part 2
You can split the string by checking for the index of last space and using it with LEFT and RIGHT function.
DECLARE #name varchar(100)= 'John Michael Smith'
SELECT LEFT(#name,LEN(#name)-CHARINDEX(' ',REVERSE(#name))) AS [Firstname],RIGHT(#name,CHARINDEX(' ',REVERSE(#name))) AS [LastName]
--Create table from below script
create table users(id int IDENTITY(1,1) PRIMARY KEY, name varchar(50));
--Insert Record for query for testing
insert into users(name)
values('John Abraham'),
('John Mark Abraham'),
('John Vens Abraham'),
('John Abraham');
--Run below query for getting all inserted records.
select * from users;
--Run below query for getting first and last name from name
select id , name, SUBSTRING(name,0, CHARINDEX(last_name,name)) as first_name, last_name from
(
select id, name, REVERSE(SUBSTRING(REVERSE(name),0,CHARINDEX(' ',REVERSE(name)))) as last_name from users
) as A
You can hi-jack 'parsename'. This only works up to 4 intervals but a nice option;
declare #name varchar(100)
set #name='John Michael Smith'
select PARSENAME(REPLACE(#name,' ','.'),1) -- returns Smith
select PARSENAME(REPLACE(#name,' ','.'),2) -- returns Micheal
select PARSENAME(REPLACE(#name,' ','.'),3) -- Returns John
select PARSENAME(REPLACE(#name,' ','.'),4) -- returns NULL

SQL Extract Values from a String

How do I extract values from a string? I'm trying to separate into 3 new columns. A separate column for city, state and zipcode.
I've tried
select address2,
left(address2, charindex('',address2)-1)
from table
and ---when I try the below code I get "Invalid length parameter passed to the left or substring function"
,LTRIM(substring(a.Address2, CHARINDEX(' ', a.Address2)+1, CHARINDEX(' ', substring(a.address2, charindex(' ',
a.address2)+1, len(a.address2)))-1))
I can break out the city (except for West Warwick) using the following code, but not sure how to make it work for state and zip. This also removes the error.
SUBSTRING(Address2,1,CHARINDEX(' ', a.address2+ ' ')-1) as city
Any ideas what to try?
It looks like your zip codes and your states are all the same length. If that is true, you should be able to use something like this:
SELECT
LEFT(a.Address2,LEN(a.Address2) - 13) AS City,
RIGHT(LEFT(a.Address2,LEN(a.Address2) - 11),2) AS State,
RIGHT(a.Address2,10) AS Zip_Code
FROM
table;
DEMO CODE
Create the table and data:
CREATE TABLE MyTable (Address2 VARCHAR(100));
INSERT INTO MyTable
VALUES
('SAN DIEGO CA 92128-1234'),
('WEST WARWICK RI 02893-1349'),
('RICHMOND IN 47374-9409');
The query:
SELECT
LEFT(Address2,LEN(Address2) - 13) AS City,
RIGHT(LEFT(Address2,LEN(Address2) - 11),2) AS State,
RIGHT(Address2,10) AS Zip_Code
FROM
MyTable;
The output:
Since you only have 3 parts (City/State/Zip) you can take advantage of a function called parsename in SQL Server 2008 and later. (The original intent of the function is to parse out object names.)
Using a combination of the replace and parsename functions will allow you to be able to separate the data into 3 parts, even if the length of the State (not likely) or the Zip (more likely) change.
Example Data:
create table #my_table
(
address2 varchar(75) not null
)
insert into #my_table values ('CONNERSVILLE IN 47331-3351')
insert into #my_table values ('WEST WARWICK RI 02893-1349')
insert into #my_table values ('RICHMOND IN 47374-9409')
insert into #my_table values ('WILLIAMSBURG IN 47393-9617')
insert into #my_table values ('FARMERSVILLE OH 45325-9226')
--this record is an example of a likely scenario for when the zip length would change.
insert into #my_table values ('WILLIAMSBURG IN 47393')
Solution:
with len_vals as
(
select t.address2
, len(parsename(replace(t.address2,' ','.'), 1)) as zip_len
, len(parsename(replace(t.address2,' ','.'), 2)) as st_len
from #my_table as t
group by t.address2
)
select left(a.address2, len(a.address2) - b.zip_len - b.st_len - 2) as city
, substring(a.address2, len(a.address2) - b.zip_len - 2, b.st_len) as st
, right(a.address2, b.zip_len) as zip_code
from #my_table as a
inner join len_vals as b on a.address2 = b.address2
Results: