SQLite: isolating the file extension from a path - sqlite

I need to isolate the file extension from a path in SQLite. I've read the post here (SQLite: How to select part of string?), which gets 99% there.
However, the solution:
select distinct replace(column_name, rtrim(column_name, replace(column_name, '.', '' ) ), '') from table_name;
fails if a file has no extension (i.e. no '.' in the filename), for which it should return an empty string. Is there any way to trap this please?
Note the filename in this context is the bit after the final '\'- it shouldn't be searching for'.'s in the full path, as it does at moment too.
I think it should be possible to do it using further nested rtrims and replaces.

Thanks. Yes, you can do it like this:
1) create a scalar function called "extension" in QtScript in SQLiteStudio
2) The code is as follows:
if ( arguments[0].substring(arguments[0].lastIndexOf('\u005C')).lastIndexOf('.') == -1 )
{
return ("");
}
else
{
return arguments[0].substring(arguments[0].lastIndexOf('.'));
}
3) Then, in the SQL query editor you can use
select distinct extension(PATH) from DATA
... to itemise the distinct file extensions from the column called PATH in the table called DATA.
Note that the PATH field must contain a backslash ('\') in this implementation - i.e. it must be a full path.

Related

Xquery delete leaves empty lines in xml document - how to remove them? (eXist-db)

In XQuery 3.1 (eXist 4.7) I have an operation that deletes nodes from a stored XML document at /db/apps/myapp/data/list_bibliography.xml that looks like this:
<listBibl xmlns="http://www.tei-c.org/ns/1.0" xml:id="bibliography">
<tei:biblStruct xmlns:tei="http://www.tei-c.org/ns/1.0" type="book" xml:id="Z-BF2WLW8Y">
<tei:monogr>
<tei:title level="m">footitle1</tei:title>
<tei:author>
<tei:name>author name</tei:name>
</tei:author>
<tei:imprint>
<tei:publisher>some city</tei:publisher>
<tei:date>2019</tei:date>
</tei:imprint>
</tei:monogr>
</tei:biblStruct>
<tei:biblStruct xmlns:tei="http://www.tei-c.org/ns/1.0" type="book" xml:id="Z-4KF7YNP3">
<tei:monogr>
<tei:title level="m">footitle2</tei:title>
<tei:author>
<tei:name>author name</tei:name>
</tei:author>
<tei:imprint>
<tei:publisher>some other city</tei:publisher>
<tei:date>2018</tei:date>
</tei:imprint>
</tei:monogr>
</tei:biblStruct>
</listBibl>
The following function:
declare local:delete-bibl()
{
let $bibdoc := doc("/db/apps/myapp/data/list_bibliography.xml")
for $bib in $bibdoc//tei:biblStruct[#xml:id = "Z-BF2WLW8Y"]
return update delete $bib
};
leaves the file with whitespace like this:
<listBibl xmlns="http://www.tei-c.org/ns/1.0" xml:id="bibliography">
<tei:biblStruct xmlns:tei="http://www.tei-c.org/ns/1.0" type="book" xml:id="Z-4KF7YNP3">
<tei:monogr>
<tei:title level="m">footitle2</tei:title>
<tei:author>
<tei:name>author name</tei:name>
</tei:author>
<tei:imprint>
<tei:publisher>some other city</tei:publisher>
<tei:date>2018</tei:date>
</tei:imprint>
</tei:monogr>
</tei:biblStruct>
</listBibl>
Is there some sort of configuration or function that can collapse the white space left by delete?
I tried using instead return update replace $bib with "" but that throws errors as the replacement must be a node.
Many thanks.
There is no configuration option for collapsing the whitespace left by eXist's XQuery Update delete operations.
To work around the error you received when replacing $bib with an empty string, instead replace it with a text node:
update replace $bib with text { "" }

Workaround for case-sensitive input to dir

I am using Octave 5.1.0 on Windows 10 (x64). I am parsing a series of directories looking for an Excel spreadsheet in each directory with "logbook" in its filename. The problem is these files are created by hand and the filenaming isn't consistent: sometimes it's "LogBook", other times it's "logbook", etc...
It looks like the string passed as input to the dir function is case-sensitive so if I don't have the correct case, dir returns an empty struct. Currently, I am using the following workaround, but I wondered if there was a better way of doing this (for a start I haven't captured all possible upper/lower case combinations):
logbook = dir('*LogBook.xls*');
if isempty(logbook)
logbook = dir('*logbook.xls*');
if isempty(logbook)
logbook = dir('*Logbook.xls*');
if isempty(logbook)
logbook = dir('*logBook.xls*');
if isempty(logbook)
error(['Could not find logbook spreadsheet in ' dir_name '.'])
end
end
end
end
You need to get the list of filenames (either via readdir, dir, ls), and then search for the string in that list. If you use readdir, it can be done like this:
[files, err, msg] = readdir ('.'); # read current directory
if (err != 0)
error ("failed to readdir (error code %d): %s", msg);
endif
logbook_indices = find (cellfun (#any, regexpi (files, 'logbook'));
logbook_filenames = files(logbook_indices);
A much less standard approach could be:
glob ('*[lL][oO][gG][bB][oO][kK]*')

How to use SQLitePCL execute content of sql file

I'm trying to use SQLitePCL package to develop a simple UWP app that executes database commands (create-select-update-delete). I created a database sql file that contains some sqlite commands and I'm trying to execute them in my code:
Uri appUri = new Uri("ms-appx:///Assets/db.sql");
StorageFile sFile = StorageFile.GetFileFromApplicationUriAsync(appUri).AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
string sSQL = FileIO.ReadTextAsync(sFile).AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
ISQLiteStatement cnStatement = dbConnection.Prepare(sSQL);
cnStatement.Step();
But when I run the program, it only executes the first statement in the sql file which is CREATE command and exit without executing the rest of the commands. Here is the sample content of the sql file:
CREATE TABLE Superhero (
Type TEXT PRIMARY KEY,
Picture TEXT
);
INSERT INTO Superhero (
Type,
Picture
)
VALUES (
'batman',
'batman.ico'
);
Anyone knows if there is a way in SQLitePCL to execute a sql file?
Any help would be very much appreciated!
Thanks!
According to the description of sqlite3_prepare interface:
These routines only compile the first statement in zSql, so *pzTail is left pointing to what remains uncompiled.
So that it seems like only the first statement in the commands is actually executed. The remainder is silently ignored. Since every command is ended up with symbol ";", for a quick and simple solution, you may just split the sql commands into single statements and then execute one by one. For example:
string sSQL = FileIO.ReadTextAsync(sFile).AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
var dbConnection = new SQLiteConnection("sun.db", SQLiteOpen.READWRITE);
//using (ISQLiteStatement cnStatement = dbConnection.Prepare(sSQL))
//{
// var result = cnStatement.Step();
//}
var statements = sSQL.Split(new[] { ';' });
foreach (string onestate in statements)
{
using (ISQLiteStatement cnStatement = dbConnection.Prepare(onestate))
{
var result = cnStatement.Step();
}
}
Otherwise, you may need to update the SQLitePCL Nuget package.

To list files based on unique part of the filename in Unix

I've a directory with below files in it -
111-xxx-typec_2015-10-13.csv.gz
111-xxx-typec_2015-10-14.csv.gz
222-yyy-typec_2015-10-13.csv.gz
222-yyy-typec_2015-10-14.csv.gz
333-zzz-typec_2015-10-13.csv.gz
333-zzz-typec_2015-10-14.csv.gz
444-ppp-typec_2015-10-13.csv.gz
444-ppp-typec_2015-10-14.csv.gz
444-ppp-typec_2015-10-15.csv.gz
I want to see the oldest file of each type (xxx, yyy, etc) only, i.e. the output should be,
111-xxx-typec_2015-10-13.csv.gz
222-yyy-typec_2015-10-13.csv.gz
333-zzz-typec_2015-10-13.csv.gz
444-ppp-typec_2015-10-13.csv.gz
Is there a way to do this?
What you could do is do an 'ls', pipe it through an 'AWK' script where you match the 'type', and check it against a dictionary. If it is in the list, ignore, otherwise print and add to list.
Something like this nawk script:
{
match($0, /(.*)-typec/, m);
if (matches[m[1]] == "")
{
print ;
matches[m[1]] = m[1];
}
}

xQuery substring problem

I now have a full path for a file as a string like:
"/db/Liebherr/Content_Repository/Techpubs/Topics/HyraulicPowerDistribution/Released/TRN_282C_HYD_MOD_1_Drive_Shaft_Rev000.xml"
However, now I need to take out only the folder path, so it will be the above string without the last back slash content like:
"/db/Liebherr/Content_Repository/Techpubs/Topics/HyraulicPowerDistribution/Released/"
But it seems that the substring() function in xQuery only has substring(string,start,len) or substring(string,start), I am trying to figure out a way to specify the last occurence of the backslash, but no luck.
Could experts help? Thanks!
Try out the tokenize() function (for splitting a string into its component parts) and then re-assembling it, using everything but the last part.
let $full-path := "/db/Liebherr/Content_Repository/Techpubs/Topics/HyraulicPowerDistribution/Released/TRN_282C_HYD_MOD_1_Drive_Shaft_Rev000.xml",
$segments := tokenize($full-path,"/")[position() ne last()]
return
concat(string-join($segments,'/'),'/')
For more details on these functions, check out their reference pages:
fn:tokenize()
fn:string-join()
fn:replace can do the job with a regular expression:
replace("/db/Liebherr/Content_Repository/Techpubs/Topics/HyraulicPowerDistribution/Released/TRN_282C_HYD_MOD_1_Drive_Shaft_Rev000.xml",
"[^/]+$",
"")
This can be done even with a single XPath 2.0 (subset of XQuery) expression:
substring($fullPath,
1,
string-length($fullPath) - string-length(tokenize($fullPath, '/')[last()])
)
where $fullPath should be substituted with the actual string, such as:
"/db/Liebherr/Content_Repository/Techpubs/Topics/HyraulicPowerDistribution/Released/TRN_282C_HYD_MOD_1_Drive_Shaft_Rev000.xml"
The following code tokenizes, removes the last token, replaces it with an empty string, and joins back.
string-join(
(
tokenize(
"/db/Liebherr/Content_Repository/Techpubs/Topics/HyraulicPowerDistribution/Released/TRN_282C_HYD_MOD_1_Drive_Shaft_Rev000.xml",
"/"
)[position() ne last()],
""
),
"/"
)
It seems to return the desired result on try.zorba-xquery.com. Does this help?

Resources