I'm trying to use INSTR function in SQLite but it returns wrong value If I use UTF8 character. How can I avoid this problem?
select instr('akçe', 'a'); --returns 1 (Correct)
select instr('akçe', 'k'); --returns 2 (Correct)
select instr('akçe', 'ç'); --returns 0 (Wrong)
select instr('akçe', 'e'); --returns 3 (Wrong)
Works for me:
> select instr('akçe', 'ç');
3
> select instr('akçe', 'e');
4
Apparently, you are not actually using UTF-8.
Check that the output of select quote(cast('ç' as blob)); is X'C3A7'.
Related
For example, where the element is 'hi', and where N is 3, I need a PostgreSQL snippet I can use in a SELECT query that returns the following array:
['hi', 'hi', 'hi']
Postgres provides array_fill for this purpose, e.g.:
SELECT array_fill('hi'::text, '{3}');
SELECT array_fill('hi'::text, array[3]);
The two examples are equivalent but the 2nd form is more convenient if you wish to replace the dimension 3 with a variable.
See also: https://www.postgresql.org/docs/current/functions-array.html
You may use array_agg with generate_series
select array_agg(s) from ( values('hi')) as t(s) cross join generate_series(1,3)
Generic
select array_agg(s) from ( values(:elem)) as t(s) cross join generate_series(1,:n)
DEMO
sql demo
with cte as (
select 'hi' as rep_word, generate_series(1, 3) as value
) -- ^^^ n = 3
select array(SELECT rep_word::text from cte);
I have a column called 'uri' which has values as follows:
file://c:\file1.txt
file://\\1.1.1.1\folder1\folder1a\file2.txt
file://d:\sub1\sub2\sub3\file3.txt
I'm trying to remove the filename from the uri to leave
file://c:\
file://\\1.1.1.1\folder1\folder1a\
file://d:\sub1\sub2\sub3\
You can use regexp_replace:
with t (col) as (
select 'file://c:\file1.txt' union all
select 'file://\\1.1.1.1\folder1\folder1a\file2.txt' union all
select 'file://d:\sub1\sub2\sub3\file3.txt'
)
select regexp_replace(col, '(^.*?)[^\\]*$', '\1') as output from t;
Produces:
output
---------------------------------
file://c:\
file://\\1.1.1.1\folder1\folder1a\
file://d:\sub1\sub2\sub3\
Demo
I am recording the connection and disconnection time of a device in a table.
The final purpose is to define the maximum disconnection time.
My table looks like this
Before proceeding with the maximum DATEDIFF calculation I tried to attempt a DATEDIFF between each disconnection-connection rows (see the picture below):
The query is obviously wrong because it is making a difference between all of the "Disconnected" and "Connected" rows.
What am I missing?
Thank you
Try this, Note that negative value implies that the connection is still active
;WITH cte_Connectivity(DeviseID, EventTime, EventType) AS
(
SELECT 1,'2017-3-24 00:01:00.000', 'On' UNION ALL
SELECT 1,'2017-3-24 00:02:00.000', 'Off' UNION ALL
SELECT 2,'2017-3-24 00:01:00.000', 'On' UNION ALL
SELECT 2,'2017-3-24 00:04:00.000', 'Off' UNION ALL
SELECT 3,'2017-3-24 00:01:00.000', 'On' UNION ALL
SELECT 4,'2017-3-24 00:01:00.000', 'On' UNION ALL
SELECT 4,'2017-3-24 00:06:00.000', 'Off' UNION ALL
SELECT 5,'2017-3-24 00:01:00.000', 'On' UNION ALL
SELECT 5,'2017-3-24 00:10:00.000', 'Off'
)
SELECT a.DeviseID,
a.EventTime,
DATEDIFF(MINUTE, a.EventTime, ISNULL(b.EventTime, DATEADD(minute, - 1, a.EventTime))) AS TimeConnected
FROM cte_Connectivity a
LEFT JOIN cte_Connectivity b
ON CASE
WHEN a.EventType = 'On'
THEN 1
ELSE NULL
END = CASE
WHEN b.EventType = 'Off'
THEN 1
ELSE NULL
END
AND a.DeviseID = b.DeviseID
WHERE a.EventType = 'ON'
I then easily solved the problem:
created two views (one with only on, starting from the thrid row, and the other with only off rows)
joined both tables and added another column with a DATEDIFF
then create a new view that looks for the maximum datediff
... nothing special, thank you again folks!
I've found a small annoyance that I was wondering how to get around...
In a simplified example, say I need to return "TEST B-19" and "TEST B-20"
I have a where clause that looks like:
where [Name] LIKE 'TEST B-[12][90]'
and it works... unless there's a "TEST B-10" or "TEST-B29" value that I don't want.
I'd rather not resort to doing both cases, because in more complex situations that would become prohibitive.
I tried:
where [Name] LIKE 'TEST B-[19-20]'
but of course that doesn't work because it is looking for single characters...
Thoughts? Again, this is a very simple example, I'd be looking for ways to grab ranges from 16 to 32 or 234 to 459 without grabbing all the extra values that could be created.
EDITED to include test examples...
You might see "TEXAS 22" or "THX 99-20-110-B6" or "E-19" or "SOUTHERN B" or "122 FLOWERS" in that field. The presense of digits is common, but not a steadfast rule, and there are absolutely no general patterns for hypens, digits, characters, order, etc.
I would divide the Name column into the text parts and the number parts, and convert the number parts into an integer, and then check if that one was between the values. Something like:
where cast(substring([Name], 7, 2) as integer) between 19 and 20
And, of course, if the possible structure of [Name] is much more complex, you'd have to calculate the values for 7 and 2, not hardcode them....
EDIT: If you want to filter out the ones not conforming to the pattern first, do the following:
where [Name] LIKE '%TEST B-__%'
and cast(substring([Name], CHARINDEX('TEST B-', [Name]) + LEN('TEST B-'), 2) as integer) between 19 and 20
Maybe it's faster using CHARINDEX in place of the LIKE in the topmost line two, especially if you put an index on the computed value, but... That is only optimization... :)
EDIT: Tested the procedure. Given the following data:
jajajajajajajTEST B-100
jajajajajajajTEST B-85
jajajajjTEST B-100
jajjajajTEST B-100
jajajajajajajTEST B-00
jajajajaTEST B-100
jajajajajajajEST B-99
jajajajajajajTEST B-100
jajajajajajajTEST B-19
jajajajjTEST B-100
jajjajajTEST B-120
jajajajajajajTEST B-00
jajajajaTEST B-150
jajajajajajajEST B-20
TEST B-20asdfh asdfkh
The query returns the following rows:
jajajajajajajTEST B-19
TEST B-20asdfh asdfkh
Wildcards or no, you still have to edit the query every time you want to change the range definition. If you're always dealing with a range (and it's not always the same range), you might use parameters. For example:
note: for some reason (this has happened in many other posts as well), when I try to post code beginning with 'declare', SO hangs and times-out. I reported it on meta already, but nobody could reproduce it (including me). Here it's happening again, so I took the 'D' off, and now it works. I'll come back tomorrow, and it will let me put the 'D' back on.
DECLARE #min varchar(5)
DECLARE #max varchar(5)
SET #min = 'B-19'
SET #max = 'B-20'
SELECT
...
WHERE NAME BETWEEN #min AND #max
You should avoid formatting [NAME] as others have suggested (using function on it) -- this way, your search can benefit from an index on it.
In any case -- you might re-consider your table structure. It sounds like 'TEST B-19' is a composite (non-normalized) value of category ('TEST') + sub-category ('B') + instance ('19'). Put it in a lookup table with 4 columns (id being the first), and then join it by id in whatever query needs to output the composite value. This will make searching and indexing much easier and faster.
In the absence of test data, I generated my own. I just removed the Test B- prefix, converted to int and did a Between
With Numerals As
(
Select top 100 row_number() over (order by name) TestNumeral
from sys.columns
),
TestNumbers AS
(
Select 'TEST B-' + Convert (VarChar, TestNumeral) TestNumber
From Numerals
)
Select *
From TestNumbers
Where Cast (Replace (TestNumber, 'TEST B-', '') as Integer) between 1 and 16
This gave me
TestNumber
-------------------------------------
TEST B-1
TEST B-2
TEST B-3
TEST B-4
TEST B-5
TEST B-6
TEST B-7
TEST B-8
TEST B-9
TEST B-10
TEST B-11
TEST B-12
TEST B-13
TEST B-14
TEST B-15
TEST B-16
This means, however, that if you have different strategies for naming tests, you would have to remove all different kinds of prefixes.
Now, on the other hand, if your Test numbers are in the TEST-Space-TestType-Hyphen-TestNumber format, you could use PatIndex and SubString
With Numerals As
(
Select top 100 row_number() over (order by name) TestNumeral
from sys.columns
),
TestNumbers AS
(
Select 'TEST B-' + Convert (VarChar, TestNumeral) TestNumber
From Numerals
Where TestNumeral Between 10 and 19
UNION
Select 'TEST A-' + Convert (VarChar, TestNumeral) TestNumber
From Numerals
Where TestNumeral Between 20 and 29
)
Select *
From TestNumbers
Where Cast (SubString (TestNumber, PATINDEX ('%-%', TestNumber)+1, Len (TestNumber) - PATINDEX ('%-%', TestNumber)) as Integer) between 16 and 26
That should yield the following
TestNumber
-------------------------------------
TEST A-20
TEST A-21
TEST A-22
TEST A-23
TEST A-24
TEST A-25
TEST A-26
TEST B-16
TEST B-17
TEST B-18
TEST B-19
All of your examples seem to have the test numbers at the end. So if you can create a table of patterns and then JOIN using a LIKE statement, you may be able make it work. Here is an example:
;
With TestNumbers As
(
select 'E-1' TestNumber
union select 'E-2'
union select 'E-3'
union select 'E-4'
union select 'E-5'
union select 'E-6'
union select 'E-7'
union select 'SOUTHERN B1'
union select 'SOUTHERN B2'
union select 'SOUTHERN B3'
union select 'SOUTHERN B4'
union select 'SOUTHERN B5'
union select 'SOUTHERN B6'
union select 'SOUTHERN B7'
union select 'Southern CC'
union select 'Southern DD'
union select 'Southern EE'
union select 'TEST B-1'
union select 'TEST B-2'
union select 'TEST B-3'
union select 'TEST B-4'
union select 'TEST B-5'
union select 'TEST B-6'
union select 'TEST B-7'
union select 'TEXAS 1'
union select 'TEXAS 2'
union select 'TEXAS 3'
union select 'TEXAS 4'
union select 'TEXAS 5'
union select 'TEXAS 6'
union select 'TEXAS 7'
union select 'THX 99-20-110-B1'
union select 'THX 99-20-110-B2'
union select 'THX 99-20-110-B3'
union select 'THX 99-20-110-B4'
union select 'THX 99-20-110-B5'
union select 'THX 99-20-110-B6'
union select 'THX 99-20-110-B7'
union select 'Southern AA'
union select 'Southern CC'
union select 'Southern DD'
union select 'Southern EE'
),
Prefixes as
(
Select 'TEXAS ' TestPrefix
Union Select 'THX 99-20-110-B'
Union Select 'E-'
Union Select 'SOUTHERN B'
Union Select 'TEST B-'
)
Select TN.TestNumber
From TestNumbers TN, Prefixes P
Where 1=1
And TN.TestNumber Like '%' + P.TestPrefix + '%'
And Cast (REPLACE (Tn.TestNumber, p.TestPrefix, '') AS INTEGER) between 4 and 6
This will give you
TestNumber
----------------
E-4
E-5
E-6
SOUTHERN B4
SOUTHERN B5
SOUTHERN B6
TEST B-4
TEST B-5
TEST B-6
TEXAS 4
TEXAS 5
TEXAS 6
THX 99-20-110-B4
THX 99-20-110-B5
THX 99-20-110-B6
(15 row(s) affected)
Is this acceptable:
WHERE [Name] IN ( 'TEST B-19', 'TEST B-20' )
The list of values can come from a subquery, e.g.:
WHERE [Name] IN ( SELECT [Name] FROM Elsewhere WHERE ... )
having a sql e.g. something like the following resulting in some rows with one value.
I search a different sql than SELECT * FROM some_sql which results in one row with comma separated values.
WITH some_sql AS (
SELECT 1 FROM DUAL
UNION
SELECT 2 FROM DUAL
)
SELECT * FROM some_sql
this SQL results in the two rows with value 1 and 2.
I seach a SQl resulting in 1,2 without changing the code of 'some_sql'.
Consider http://halisway.blogspot.com/2006/08/oracle-groupconcat-updated-again.html
Sice you are on 11G you can use LISTAGG
WITH some_sql AS (
SELECT 1 x FROM DUAL
UNION
SELECT 2 x FROM DUAL
)
SELECT LISTAGG(x, ',') WITHIN GROUP(ORDER BY x) FROM some_sql