I have a table in sqlite db called [tblbook] with a column [authors]. What I am trying to do in the sql is to split the author values to firstname and the lastname and sort it on lastname. I did find this great code:
SELECT substr(BookAuthor, 1, NULLIF(CHARINDEX(' ', BookAuthor) - 1, -1)) AS [FirstName],
substr(BookAuthor, CHARINDEX(' ', BookAuthor) + 1, LEN(BookAuthor)) AS [LastName]
FROM tblBook where _id=3
It works perfectly on MSSQL but sqlite doesn't have the charindex function hence it fails.
Could anyone please be kind and advise me what should be the best approach to achieve this.
Another way (a little shorter) to write this would be
SELECT
substr(BookAuthor, 1, instr(BookAuthor, ' ') - 1) AS first_name,
substr(BookAuthor, instr(BookAuthor, ' ') + 1) AS last_name
FROM tblBook where id=3
ORDER BY last_name
This would apply for version 3.7.15 and beyond.
Unfortunately this functionality is missing from SQLite:
http://www.sqlite.org/lang_corefunc.html
Index of substring in SQLite3?
Maybe you can feed your custom string position function to SQLite using http://www.sqlite.org/c3ref/create_function.html
But if you really need it, there is a complex, ineffective workaround:
http://sqlfiddle.com/#!7/e03a4/3
1: create a numbers table/view
2: join authors to numbers table, and choose the MIN position of the space
3: now you can split the names
SELECT
substr( name, 1, pos-1) AS first_name,
substr( name, pos+1) AS last_name
FROM (
SELECT
author.name,
numbers.x AS pos
FROM author
INNER JOIN numbers
WHERE substr( author.name, numbers.x, 1) = ' '
GROUP BY author.name
) AS a
ORDER BY last_name;
Related
select distinct substr(value,2,4),summary
from ticket_custom
LEFT JOIN ticket On ticket_custom.substr(value,2,4) = ticket.id
where name = "parent" AND value <> 0
I have a table ticket_custom where the ticket-number has a hastag in front of the ticketnumber (e.g. "#4567"), but in the table ticket, the ticketnumber is saved without this hashtag ("4567").
I would like to left join these two tables and would like to use the "summary"-value of the table ticket right next to the ticket-number without the #. I tried the above query, but I am getting an error. How can I combine substr = using the ticketnumber without the # with a left join? Or is there another way to do this?
Thanks!
You should be doing substr(ticket_custom.value,2) instead of ticket_custom.substr(value,2,4) (syntax was incorrect, and string length isn't guaranteed only to be 5 chars)
So your query should look like:
select distinct substr(value,2),summary
from ticket_custom
LEFT JOIN ticket On substr(ticket_custom.value,2) = ticket.id
where name = "parent" AND value <> 0
This is the correct syntax for the function substr():
On substr(ticket_custom.value,2,4) = ticket.id
or
On substr(ticket_custom.value,2) = ticket.id
if ticket_custom.value contains only 5 characters.
In this case (only 5 characters) you can use replace():
On replace(ticket_custom.value, '#', '') = ticket.id
or simply:
On ticket_custom.value = '#' || ticket.id
I'm trying to replace a placeholder string inside a selection of 10 random records with a random string (a name) taken from another table, using only sqlite statements.
i've done a subquery in order to replace() of the placeholder with the results of a subquery. I thought that each subquery loaded a random name from the names table, but i've found that it's not the case and each placeholder is replaced with the same string.
select id, (replace (snippet, "%NAME%", (select
name from names
where gender = "male"
) )
) as snippet
from imagedata
where timestamp is not NULL
order by random()
limit 10
I was expecting for each row of the SELECT to have different random replacement every time the subquery is invoked.
hello i'm %NAME% and this is my house
This is the car of %NAME%, let me know what you think
instead each row has the same kind of replacement:
hello i'm david and this is my house
This is the car of david, let me know what you think
and so on...
I'm not sure it can be done inside sqlite or if i have to do it in php over two different database queries.
Thanks in advance!
Seems that random() in the subquery is only evaluated once.
Try this:
select
i.id,
replace(i.snippet, '%NAME%', n.name) snippet
from (
select
id,
snippet,
abs(random()) % (select count(*) from names where gender = 'male') + 1 num
from imagedata
where timestamp is not NULL
order by random() limit 10
) i inner join (
select
n.name,
(select count(*) from names where name < n.name and gender = 'male') + 1 num
from names n
where gender = 'male'
) n on n.num = i.num
I have phone number field in database. It has already data.
I want to change my phone number format to "XXX-XXX-XXXX"
Current database has no any phone format.
So there may be garbage data. I have already applied validation for new records but now I want to change my existing data also.
Is there any specific way through that I can change my existing data. And make all phone numbers to follow this format.
Please advice.
Create function to remove the non-numeric data and do the formatting
CREATE FUNCTION [UDF_STRIP_NONNUMERIC_DATA](#str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
WHILE Patindex('%[^0-9]%', #str) > 0
BEGIN
SET #str = Stuff(#str, Patindex('%[^0-9]%', #str), 1, '')
END
RETURN #str
END
You can use STUFF function to inset the - between phone number
Select left(Stuff(Stuff(dbo.[UDF_STRIP_NONNUMERIC_DATA](Phone),4,0,'-'),8,0,'-'),12)
From yourtable
If you are using SQL SERVER 2012+ use can use FORMAT function (thanks to LukStorms, who mentioned it in comment)
SELECT Format(Cast(dbo.[Udf_strip_nonnumeric_data](Phone) AS BIGINT), '###-###-####')
FROM yourtable
To update
Update yourtable
SET phone = left(Stuff(Stuff(dbo.[UDF_STRIP_NONNUMERIC_DATA](Phone),4,0,'-'),8,0,'-'),12)
Demo
declare #str varchar(100)= '9225-123-4567'
select left(Stuff(Stuff(dbo.[UDF_STRIP_NONNUMERIC_DATA](#str),4,0,'-'),8,0,'-'),12)
Result : 922-512-3456
declare #phone varchar(24)
set #phone = '(334)789-4532'
--set #phone = '314789-4532'
--set #phone = '3457894532'
--set #phone = '534-789-4532'
SELECT
LEFT(N,3) + '-' + SUBSTRING(N,4,3) + '-' + RIGHT(N,4)
FROM
(SELECT CAST(CAST((
SELECT SUBSTRING(#phone, Number, 1)
FROM master..spt_values
WHERE Type='p' AND Number <= LEN(#phone) AND
SUBSTRING(#phone, Number, 1) LIKE '[0-9]' FOR XML Path(''))
AS xml) AS varchar(MAX)) as N) as N
Ok, to replace all non-numeric characters, look at this.
Here is a sample script (copied from that link) to show you how it works (You'll need to modify this to fit your table name and column names:
-- Step 1: creates table to use to hold every char in every phone number
if object_id('dbo.tally') is not null drop table dbo.tally
select top 10000 --change to fit max length of phone number
identity(int,1,1) as n
into dbo.tally
from master.dbo.syscolumns sc1,
master.dbo.syscolumns sc2
-- add pk to maximize performance
alter table dbo.tally
add constraint pk_tally_n
primary key clustered (n) with fillfactor = 100
-- Step 2: Create temporary table holding three bad phone numbers
declare #phonetable table
(uniqueid int identity(1,1),
phone_number varchar(500))
insert into #phonetable (phone_number)
select '01234-567-890' union
select '012345 6789ext' union
select 'n/a' union select '...12345.....';
-- Step 3: identify, for every character, whether it is a number or not,
and remove the non-numeric ones
with cte (uniqueid, phone_number, goodchar, badchar) as
( select uniqueid, phone_number,
case when substring(phone_number,N,1) not like '%[^0-9]%'
then substring(phone_number,N,1) end as goodchar,
case when substring(phone_number,N,1) like '%[^0-9]%'
then substring(phone_number,N,1) end as badchar
from #phonetable , Tally
where phone_number like '%[^0-9]%' and N <= len(phone_number) )
select distinct phone_number,
isnull( stuff (
( SELECT '' + goodchar
FROM cte t1
where t1.UniqueID = t2.UniqueID
FOR XML PATH ( '' ) ) , 1 , 0 , '' ) ,'')
as clean_phone_number from cte t2
to display the numbers with formatting, just extract the appropriate pieces and re-concatenate them with the dashes.
Select case len(phone)
When 10 then left(phone, 3) + '-' +
substring(phone, 4,3) + '-' +
substring(phone, 7,4)`
When 7 then left(phone, 3) + '-' +
substring(phone, 4,4)
Else '' end
To create a computed column
Alter table Add Column FormattedPhone as
case len(phone)
When 10 then left(phone, 3) + '-' +
substring(phone, 4,3) + '-' +
substring(phone, 7,4)`
When 7 then left(phone, 3) + '-' +
substring(phone, 4,4)
Else '' end
If you don't mind a UDF
Select [dbo].[udf-Str-Format-Phone]('334)789-4532')
Returns
334-789-4532
The UDF
CREATE FUNCTION [dbo].[udf-Str-Format-Phone] (#S varchar(max))
Returns varchar(25)
AS
Begin
Declare #Return varchar(25)
;with cte0(N) As (Select 1 From (Values(1),(1),(1),(1),(1)) N(N))
, cteN(N) As (Select Top (Len(#S)) Row_Number() over (Order By (Select NULL)) From cte0 N1, cte0 N2)
, cteS(S) As (Select Substring(#S,N,1) From cteN Where Substring(#S, N, 1) LIKE '[0-9]' FOR XML Path(''))
Select #Return = IIf(Len(S)>=10,Stuff(stuff(S,4,0,'-'),8,0,'-'),Stuff(S,4,0,'-')) From cteS
Return #Return
End
-- Syntax : Select [dbo].[udf-Str-Format-Phone]('(334)789-4532') -- Returns 334-789-4532
-- Syntax : Select [dbo].[udf-Str-Format-Phone]('Phone:7894532') -- Returns 789-4532
I have two tables Procedures and ProcedureTypes.
Procedures has a column Type which is a varchar with the values (1, 2), (3, 4), (4, 5) etc...
ProcedureType has a primary key 'ID' 1 to 9.
ID Description
1 Drug
2 Other-Drug
etc...
ID is an integer value and Type is varchar value.
Now I need to join these two tables to show the values
ID in the Procedures table
ProcedureType in the Procedures table
Description in the ProceduresType table with the value separated by a "-".
For example if he value in Type is (1,2) the new table after join should show values in the description like (Drug-Other Drug)
I have used this query bot to no avail
SELECT * FROM dbo.[Split]((select RequestType from GPsProcedures), ',')
Can anyone tell me how to do it and why the above query is not working
with Procedures as (
select 1 as ID, '1,2,3' as Typ
),
ProcedureTypes as (
select 1 as TypeID, 'Drug' as Name
union select 2 , 'Other-Drug'
union select 3 , 'Test 3'
)
/*Get one extra column of type xml*/
,Procedures_xml as (
select id,CONVERT(xml,' <root> <s>' + REPLACE(Typ,',','</s> <s>') + '</s> </root> ') as Typ_xml
from Procedures
)
/*Convert the field string to multiple rows then join to procedure types*/
, Procdure_With_Type as (
select ID,T.c.value('.','varchar(20)') as TypeID,
ProcedureTypes.Name
from Procedures_xml
CROSS APPLY Typ_xml.nodes('/root/s') T(c)
INNER JOIN ProcedureTypes ON T.c.value('.','varchar(20)') = ProcedureTypes.TypeID
)
/*Finally, group the procedures type names by procedure id*/
select id,
STUFF((
SELECT ', ' + [Name]
FROM Procdure_With_Type inn
WHERE (Procdure_With_Type.ID = inn.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS NameValues
from Procdure_With_Type
group by ID
You can't have a select statement as a parameter for a function, so instead of this:
SELECT * FROM dbo.[Split]((select RequestType from GPsProcedures), ',')
Use this:
select S.*
from GPsProcedures P
cross apply dbo.[Split](P.RequestType, ',') S
I have a table which contains a phone number column. There is no restrictions on how to enter the phone numbers. Currently the phone numbers are in the following format
123-456-7890
(123)-456-7890
1234567890
I would like to update the table and bring all phone numbers in 123-456-7890 format. I have over 20k records. Can I do that using SQL Query or I have to use regular expression in ASP or PHP?
Edit: Note best answer is for modified question, with phone number (123)-456-78790 changed to (123)456-7890
If they are strictly in one of those 3 formats, you can do it in SQL easy enough by using SUBSTRING and testing the LEN of each item.
If there are other formats, I'd suggest doing this in a language that is better at text-manipulation, such as .net.
Edit to add:
Given your comment that it'll only be those 3 formats for now, you can do this:
declare #t table (x varchar(20))
insert into #t
select '123-456-7890'
union select '(123)456-7890'
union select '1234567890'
select
case
when len(x) = 10 then
substring(x, 1, 3) + '-' + substring(x, 4, 3) + '-' + substring(x, 7, 4)
when len(x) = 13 then
substring(x, 2, 3) + '-' + substring(x, 6, 8)
else x
end
from #t
This will work:
First replace the parentheses and hyphens, then add them back in.
DECLARE #Number varchar(25)
SELECT #Number = '(123)-456-7890'
SELECT SUBSTRING(REPLACE(REPLACE(REPLACE(#Number, '(', ''), ')', ''), '-', ''), 1, 3)
+ '-'
+ SUBSTRING(REPLACE(REPLACE(REPLACE(#Number, '(', ''), ')', ''), '-', ''), 4, 3)
+ '-'
+ SUBSTRING(REPLACE(REPLACE(REPLACE(#Number, '(', ''), ')', ''), '-', ''), 7, 4)
Note
You could create a scalar function to replace all the hyphens and parentheses... It would be more readable then:
DECLARE #Number varchar(25)
SELECT #Number = '(123)-456-7890'
SELECT SUBSTRING(StripCharacters(#Number), 1, 3)
+ '-'
+ SUBSTRING(StripCharacters(#Number), 4, 3)
+ '-'
+ SUBSTRING(StripCharacters(#Number), 7, 4)
Succinct and without temp tables:
UPDATE Phones
SET phone =
SUBSTRING(REPLACE(REPLACE(REPLACE(phone,'-',''),')',''),'(',''),1,3) + '-'
+ SUBSTRING(REPLACE(REPLACE(REPLACE(phone,'-',''),')',''),'(',''),4,3) + '-'
+ SUBSTRING(REPLACE(REPLACE(REPLACE(phone,'-',''),')',''),'(',''),7,4)
Here is a great example:
Shows how to create User Defined Functions, custom formatting function for telephone numbers in TSQL
I would load every phone number and strip them.
So remove all periods, commas, hyphens, - basically anything that isn't a number.
Then reinsert them in the format you're looking for.
you can do this through a query, or server side language.
If you only have 20K records then just go with whatever is easier for you. Personally, I would pull all the data and then reinsert it using a server side language. PHP, ASP, or SQL it doesn't really matter if this is a one time thing. Just be sure to set up some formatting restrictions on new inserts though.
Look at this quick example:
CREATE TABLE #temp
(
phonenumber VARCHAR(15)
)
INSERT INTO #temp
( phonenumber )
VALUES ( '555-578-5899'
INSERT INTO #temp
( phonenumber )
VALUES ( '(555)-896-3269' )
INSERT INTO #temp
( phonenumber )
VALUES ( '123-456-2129')
update #temp
set phonenumber=replace(phonenumber,'(','')
update #temp
set phonenumber=replace(phonenumber,')','')
update #temp
set phonenumber=replace(phonenumber,'-','')
-- That will eliminate all (,- and ) from the table
update #temp
set phonenumber=left(phonenumber,3)+'-'+substring(phonenumber,4,3)
+'-'+right(phonenumber,4)
SELECT * FROM #temp
DROP TABLE #temp