I am writing a query in MS Access¹ towards an Oracle database, where I am trying to find everyone incarcerated in prisons in Norway during the census of 1875. To do this, I have to search for keywords in several different fields, as the ennumerators would describe their state several different ways, e.g.:
By describing their family connection as ‘Fange’, ‘Arrestant’ (prisoner) or the likes.
By listing them as temporarily present at a location named ‘Fængsel’ (prison) or the likes.
If at their family’s home, by listing them as absent and naming their assumed location as above.
By listing them as living in a separate building, named ‘Fængsel’ or the likes.
By listing their profession as ‘Fange’, ‘Arrestant’ (v.s.) or the likes.
One of the keywords I am looking for, is variants of ‘Bodsfængsel’ (a ‘prison of penitence’). Problems is, ‘Bod’ can also mean stall/small building. To make sure I include all variants of ‘Bodsfængsel’, I have written the following lines (only the relevant code snippet is shown here; a complete section is shown below):
Or BOSTNVN Like "*bod*"
And
(
BOSTNVN not Like "*bode*" or
BOSTNVN not Like "*dbod*" or
BOSTNVN not Like "*bodg*"
)
Problem is, when I run this code, I get 8513 hits, exactly the same number of lines as when I exclude the not like-lines.
Comments:
The exclusions are to avoid hits on placenames such as ‘Toldbod’, ‘Boden’ or ‘Toldbodgade’
If I somehow could get it to output extra fields (e.g. Field0, Field1, Field2 et c.) to show where the hit was found, it would probably make it much easier to find the errors too.
I hope I have provided all necessary information. Please don’t chop my head off!
¹ Access 2007 on Win 7 Enterprise.
Here is a complete snippet from the beginning of the query; if this is not necessary, please advise, and I will remove it:
SELECT
KOMMNR, KRETSNR, BOSTNR, PERSNR,
⋮
PID
FROM
FOLKETELLINGER_PERSON_1875
WHERE
(
(
KOMMNR Not Like "11*"
And KOMMNR Not Like "12*"
⋮
And KOMMNR Not Like "17*"
)
AND (
SEDVBO Like "*Fæng*"
Or SEDVBO Like "*fæng*"
⋮
Or SEDVBO Like "*arest*"
And
(
SEDVBO not Like "*Bode*" or
SEDVBO not Like "*dBod*" or
SEDVBO not Like "*Bodg*"
)
Or SEDVBO Like "*bod*"
And
(
SEDVBO not Like "*bode*" or
SEDVBO not Like "*dbod*" or
SEDVBO not Like "*bodg*"
)
Or SEDVBO Like "*Bot*"
And
(
SEDVBO not Like "*Bote*" or
SEDVBO not Like "*dBot*" or
SEDVBO not Like "*Botg*"
)
Or SEDVBO Like "*bot*"
And
(
SEDVBO not Like "*bote*" or
SEDVBO not Like "*dbot*" or
SEDVBO not Like "*botg*"
)
)
)
OR (
⋮
);
First, SQL is not case sensitive, so you have redundant lines. E.g. these two do the same thing:
Or SEDVBO Like "*Bot*"
Or SEDVBO Like "*bot*"
You're using or in your bottom level conditions where you should be using and. If you use or it will return all records because if any one of the inclusion criteria are triggered the record would be included even if it fails all others at that same level. For example, if a value is not Like '*Bode*' it will be included even if it is like "*dBod*".
You also have your code split out in a more complex manner than necessary, if the code is meant to have the statements at the level they currently are. You can condense your SEDVBO block like this:
SEDVBO Like "*arest*"
Or SEDVBO Like "*bod*"
Or SEDVBO Like "*Bot*"
And
(
SEDVBO not Like "*Bode*" and
SEDVBO not Like "*dBod*" and
SEDVBO not Like "*Bodg*" and
SEDVBO not Like "*bote*" and
SEDVBO not Like "*dbot*" and
SEDVBO not Like "*botg*"
)
Or if you're trying to do what I think you might be, namely looking for unique combinations of Like and not Like you are missing parentheses around each or/and pairing. You'd add them like this:
(SEDVBO Like "*arest*"
And
(
SEDVBO not Like "*Bode*" and
SEDVBO not Like "*dBod*" and
SEDVBO not Like "*Bodg*"
)
)
Or
(SEDVBO Like "*bod*"
And
(
SEDVBO not Like "*bode*" and
SEDVBO not Like "*dbod*" and
SEDVBO not Like "*bodg*"
)
)
Or
(SEDVBO Like "*bot*"
And
(
SEDVBO not Like "*bote*" and
SEDVBO not Like "*dbot*" and
SEDVBO not Like "*botg*"
)
)
Your first snippet would become:
Or
(BOSTNVN Like "*bod*"
And
(
BOSTNVN not Like "*bode*" and
BOSTNVN not Like "*dbod*" and
BOSTNVN not Like "*bodg*"
)
)
Related
I am trying to display image files pulled from a server. In SSRS I have managed to do this before but recently to add security, the location was changed so each file is in its own folder which has a random string for a name.
Before I used this:
=string.Concat("/files/reports/images/",Fields!FormTutorInitials.Value, ".jpg")
Which pulled the file from its location. Each file is named after the tutors initials, so Tutor who's initials are ABC would pull their picture from /files/reports/images/ABC.jpeg. Now however, that file sits in a location like this:
/files/reports/images/rgdg5w-gtreh65-hts-56hehj-5rs333/ABC.jpeg
Is there a way to insert a LIKE clause into the code? I have tried =string.Concat("/files/reports/images/",LIKE *Fields!FormTutorInitials.Value, ".jpg") but it does not accept it.
I'm assuming you are using the expression as the image source here...
This answer assumes that the filename only exists once in the folder/subfolders.
It uses xp_cmdshell so you must be aware of the security implications of enabling this if it is not already enabled. (https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/xp-cmdshell-server-configuration-option?view=sql-server-ver15)
The way I would do this is to get a list of the files into a table variable then append this to your dataset query
As an example.
DECLARE #t TABLE(TutorName varchar(50), TutorInitials varchar(20))
INSERT INTO #t VALUES ('Dave Smith', 'DS'), ('Sally James', 'SJ'), ('Rob Jones', 'RJ'), ('Jane Bloggs', 'JB')
DECLARE #dir TABLE(filename varchar(1024))
INSERT INTO #dir
exec xp_cmdshell 'dir "\\myFileServer\ImgesRootFolder\*.png" /b /s'
SELECT DISTINCT
t.*,
MIN(d.[filename]) OVER(PARTITION BY t.TutorName, t.TutorInitials) as ImageFileName
FROM #t t
JOIN #dir d on d.[filename] like '%' + t.TutorInitials + '.png'
The first table is the 'tutors' table with names and initials, the second table contains the results of a recursive DIR command against \\myFileServer\ImgesRootFolder\*.png
Then finally all we do is join then togther.
In this example, I get the MIN() filename value so be aware that is for exmaple, DS.PNG appeared in more than one folder, only the first (alphabetically) would be returned.
The result of the query is something like this.
TutorName TutorInitials ImageFileName
Dave Smith DS \\myFileServer\ImgesRootFolder\randomfolder12345\ds.png
Jane Bloggs JB \\myFileServer\ImgesRootFolder\randomfolder68548\jb.png
Rob Jones RJ \\myFileServer\ImgesRootFolder\randomfolder96325\rj.png
Sally James SJ \\myFileServer\ImgesRootFolder\randomfolder74125\sj.png
You can now just use the ImageFileName column as the imagesource value
I am a little new to Oracle and PeopleSoft but this is my issue.
I need to filter some rows out of a database based on a couple column conditions, but if these conditions meet a different condition in a separate column they should still be included. Here is what I have so far:
SELECT * FROM PS_SAA_ACRSE_AVLVW
WHERE CATALOG_NBR NOT LIKE '%000%' AND CATALOG_NBR NOT LIKE '%900%'
This works fine, but if the CATALOG_NBR IS '900' AND SUBJECT column is 'SAA' any of these should be included.
Hopefully this makes sense.
what about OR ?
SELECT * FROM PS_SAA_ACRSE_AVLVW
WHERE ( CATALOG_NBR NOT LIKE '%000%' AND CATALOG_NBR NOT LIKE '%900%' )
OR ( CATALOG_NBR = '900' AND SUBJECT_column = 'SAA')
Is there a fairly simple way to take an input parameter containing a comma seperated list of prefixes and return a cursor based on a select statement that uses these?
i.e. (Pseudocode)
PROCEDURE get_by_prefix(p_list_of_prefixes IN varchar2, r_csr OUT SYS_REFCURSOR)
IS
BEGIN
OPEN r_csr FOR
SELECT * FROM my_table where some_column LIKE (the_individual_fields_from p_list_of_prefixes ||'%')
END
I've tried various combinations, and now have two problems - coercing the input into a suitable table (I think it needs to go into a table type rather than a VARCHAR2_TABLE), and secondly getting the like clause to be effectively a SELECT from an internal 'pseudotable'...
EDIT: It seems that people are suggesting ways to use 'IN' with a set of potential values - whereas Im looking at using LIKE. I could use a similar technique - building up dynamic SQL, but was wondering if there isnt a more elegant way...
PL/SQL has no concept of a comma-separated list and no built-in splitter as in Perl etc, so you'll have to use one of the hand-rolled methods such as this one:
https://stewashton.wordpress.com/2016/08/01/splitting-strings-surprise
(Other methods are available.) Then it's just a matter of either populating a collection in one step and using it in the next, or else combining the two as something like this:
declare
p_list_of_prefixes varchar2(100) := 'John,Jim,Jules,Janice,Jenny';
begin
open :refcur for
with params as
( select x.firstname
from xmltable(
'ora:tokenize($X, "\,")'
passing p_list_of_prefixes as x
columns firstname varchar2(4000) path '.'
) x
)
, people as
( select 'Dave Clark' as fullname from dual union all
select 'Jim Potter' from dual union all
select 'Jenny Jones' from dual
)
select x.firstname, p.fullname
from params x
left join people p on p.fullname like x.firstname || '%';
end;
Output:
FIRSTNAME FULLNAME
-------------- -----------
John
Jim Jim Potter
Jules
Janice
Jenny Jenny Jones
Using LIKE the way you want is easy, but it is the wrong solution. (See my Comment under the original post).
Anyway - if by order of your superiors, or some other semi-legitimate reason, you must use a LIKE condition, it should look something like this:
... where ',' || p_list_of_whatever || ',' like '%,' || some_column || ',%
Concatenating commas at both ends of both sides of the comparison is needed, because you don't want Jo in the column to match John in the input list. Start from there and you will see why you need the commas on the right-hand side, and then follow from there and you will see why you need them on the left also.
I have a WITH clause that gives me the desired result, and i'm trying to put it in a variable. I have omitted code for simplicity. The last line of code is most relevant.
WITH ALL_VE_ERRORS AS (
SELECT *
FROM ASN.AN_VALIDATION_ERRORS
WHERE ...
), FILTER_STATUS AS (
SELECT *
FROM ALL_VE_ERRORS
WHERE ...
) SELECT UNIT_DISCREPANCY FROM FILTER_STATUS INTO W_UNIT_DISCREPANCY; <-- like this
But this doesn't work, the compiler doesn't like this. I also tried putting it first like this:
SELECT INTO W_UNIT_DISCREPANCY <-- or like this
WITH ALL_VE_ERRORS AS (...
Anyone know the proper syntax to do something like this?
If you have no reasons I can't see, you don't need two tables in your WITH clause; you could simplify it this way:
WITH ALL_VE_ERRORS AS (
SELECT *
FROM ASN.AN_VALIDATION_ERRORS
WHERE ...
)
SELECT UNIT_DISCREPANCY
INTO W_UNIT_DISCREPANCY
FROM ALL_VE_ERRORS
WHERE ...
Otherwise, you can use:
WITH ALL_VE_ERRORS AS (
SELECT *
FROM ASN.AN_VALIDATION_ERRORS
WHERE ...
), FILTER_STATUS AS (
SELECT *
FROM ALL_VE_ERRORS
WHERE ...
)
SELECT UNIT_DISCREPANCY
INTO W_UNIT_DISCREPANCY
FROM FILTER_STATUS
See the Below Doctrine Query:
SELECT values, orgunit, form
FROM Values values
INNER JOIN values.orgunit orgunit
INNER JOIN values.form form
INNER JOIN orgunit.orgunitStructure orgunitStructure
WHERE orgunitStructure.level1Id=123032
AND orgunitStructure.level >= (SELECT selectedOrgSructure.level FROM OrgunitStructure selectedOrgSructure WHERE selectedOrgSructure.orgunit=123032 )
AND form.id IN(189,187,190,188)
AND (
LOWER(values.value) LIKE '%"189886":"10369434"%'
OR LOWER(values.value) LIKE '%"189880":"10369434"%'
OR LOWER(values.value) LIKE '%"189881":"10369434"%'
OR LOWER(values.value) LIKE '%"189871":"10369434"%'
OR LOWER(values.value) LIKE '%"189888":"10369434"%'
OR LOWER(values.value) LIKE '%"189873":"10369434"%'
OR LOWER(values.value) LIKE '%"189870":"10369434"%'
OR LOWER(values.value) LIKE '%"189863":"10369434"%'
OR LOWER(values.value) LIKE '%"189865":"10369434"%'
OR LOWER(values.value) LIKE '%"189867":"10369434"%'
OR LOWER(values.value) LIKE '%"189869":"10369434"%'
OR LOWER(values.value) LIKE '%"189872":"10369434"%'
OR LOWER(values.value) LIKE '%"189894":"10369434"%'
OR LOWER(values.value) LIKE '%"189896":"10369434"%'
OR LOWER(orgunit.longname) LIKE '%10369434%'
)
I'm looking for REGEX Optimization of the WHERE clause, specifically putting the ORs together into something like, from:
LOWER(values.value) LIKE '%"189886":"10369434"%'
OR LOWER(values.value) LIKE '%"189880":"10369434"%'
OR LOWER(values.value) LIKE '%"189881":"10369434"%'
OR LOWER(values.value) LIKE '%"189871":"10369434"%'
OR LOWER(values.value) LIKE '%"189888":"10369434"%'
OR LOWER(values.value) LIKE '%"189873":"10369434"%'
OR LOWER(values.value) LIKE '%"189870":"10369434"%'
Into:
LOWER(values.value) REGEXP '%("189886":"10369434")|("189886":"10369434")|("189880":"10369434")|("189881":"10369434")|("189871":"10369434")|("189888":"10369434")|("189873":"10369434")%'