like does not work case insensitive Postgresql - postgresql-9.1

The aim is to create a duplicate check of companies. And present suspicious records for further action.
This is done by a self join and all is well as long as there is an EXACT match (case sensitive). But 'Test' and 'test' is suspicious and should be listed. A fiddle to show the problem:
WHERE a.name ILIKE b.name
The above code is not case insensitive. Test and test is not shown.
The output should be (regardless of number of duplicated records):
1 Test 5 tesT
3 Testa 4 Testa
Modified the fiddle with 5 records. http://sqlfiddle.com/#!12/2c723/1
Thank you in advance for all clues to make an insensitive self join search!

I think I found a solution based on a simple join:
create table co (id int4, name varchar(30));
insert into co values
(1,'Test'),
(2,'test'),
(3,'Testa'),
(4,'Testa'),
(5,'testT');
SELECT min(a.id),a.name,max(b.id), b.name FROM co a
LEFT JOIN co b ON lower(a.name) = lower(b.name)
WHERE a.id<b.id
GROUP BY a.name,b.name;
The output was this:
1|Test|2|test
3|Testa|4|Testa
The goal was to present 2 duplicates at a time. Merge this 2 and do a new check for duplicates.
Thanks to "a-horse-with-no-name" for all new approaches.

Related

How do I limit query results, when distinct isn't distinct?

I have a bill of material file that I am trying to reduce to only the unique parts, and related data for the line. The problem I'm running into is multiple instances of a part number due to variations in the formatting or language in the part name from the system/s that a third party pulls the data from.
pn123 part_name
pn123 Part-name
pn123 Part name
pn123 German name
All other fields I select are equal, how do I limit this in the where clause to just one instance of the above for all different part numbers? Is there an equivalent to MAX() in a text string?
I am working around the issue in excel, by deleting the dupes.
select distinct
adhoc.ats_esh.Customs_Entry_Num
[VIN]as [Qlickview VIN]
,[Build_Date]
,[BOM_Level]
,[9802].[Supplier]
,[Part_number]
,[Part_Name] *******THIS IS THE PROBLEM FIELD*******
,[Unit_Price]
,[Usage]
,[Extended_Price]
from
adhoc.IMFM_9802_EU_AP [9802] inner join ADHOC.ATS_ESL
ON [9802].VIN = ADHOC.ATS_ESL.Part_Num
inner join adhoc.ATS_ESH
ON ADHOC.ATS_ESH.Trans_SK = ADHOC.ATS_ESL.Trans_SK
where
adhoc.ats_esh.importer ='ACME_CO'
and adhoc.ATS_ESH.ENTRY_SUMMARY_DATE >= '2/01/2018'
And adhoc.ATS_ESH.ENTRY_SUMMARY_DATE < '3/01/2018'
AND adhoc.ats_esl.Supplier in('supplier1','supplier2','supplier3')
--and adhoc.ats_esl.Part_Num like '%ABC%'
--and [BOM_Level] = '1' --**** use MAX()
The right way to do this is to have a table with part name and number where part number is a unique key. This way you join on Part_number and get a unique Part_name. You can also use Max(Part_name) if you use Group by Part_number but this will require you to rework your query a little bit.

I need the equivalent of this Count with Case for Firebird 3 database

I need the equivalent of this Count with Case for a Firebird 3 database. I get an error when I try it:
SQL error code = -104.
Invalid usage of boolean expression.
I was just recently introduced to the Case command and I can't seem to rework it myself. I managed to get it to work with SQLite just fine.
The intent is to do an AND operation, the Where can't do an AND because the keywords are in rows.
SELECT Count((CASE WHEN keywords.keyword LIKE '%purchased%'
THEN 1 END) AND
(CASE WHEN keywords.keyword LIKE '%item%'
THEN 1 END)) AS TRows
FROM products
LEFT OUTER JOIN keywords_products ON
products.product_rec_id = keywords_products.product_rec_id
LEFT OUTER JOIN keywords ON
keywords_products.keyword_rec_id = keywords.keyword_rec_id
WHERE (keywords.keyword LIKE '%purchased%' OR
keywords.keyword LIKE '%item%')
I have three SQLite tables, a products table, a keywords_products table, and a keywords table.
CREATE TABLE products (
product_rec_id INTEGER PRIMARY KEY NOT NULL,
name VARCHAR (100) NOT NULL
);
CREATE TABLE keywords_products (
keyword_rec_id INTEGER NOT NULL,
product_rec_id INTEGER NOT NULL
);
CREATE TABLE keywords (
keyword_rec_id INTEGER PRIMARY KEY NOT NULL,
keyword VARCHAR (50) NOT NULL UNIQUE
);
The keywords_products table holds the the record id of a product and a record id of a keyword. Each product can be assigned multiple keywords in the keywords table.
The keyword table looks like this:
keyword_rec_id keyword
-------------- -----------
60 melee
43 scifi
87 water
The keywords_products table looks like this (one keyword can be assigned to many products):
keyword_rec_id product_rec_id
-------------- --------------
43 1
60 1
43 2
87 3
The products table looks like this:
product_rec_id name
-------------- --------------
1 Scifi Melee Weapons
2 Scifi Ray Weapon
3 Lake House
I'm assuming you want to count how many rows there are where both conditions are true.
The error occurs because you can't use AND between integer values. The values must be true booleans.
So, change your code to
Count((CASE WHEN keywords.keyword LIKE '%purchased%'
THEN TRUE END) AND
(CASE WHEN keywords.keyword LIKE '%item%'
THEN TRUE END))
However that is far too complex. You can simplify your expression to
count(nullif(
keywords.keyword LIKE '%purchased%' and keywords.keyword LIKE '%item%',
false))
The use of NULLIF is needed because COUNT will count all non-NULL values (as required by the SQL standard), and false is non-NULL as well. So to achieve the (assumed) desired effect, we transform false to NULL using NULLIF.
You have to use ONE single CASE expression with multiple WHEN branches.
Making Boolean functions of distinct CASE expressions just makes no sense - the CASE is not Boolean function itself.
You can see rules and an example at CASE.
case
when Age >= 18 then 'Yes'
when Age < 18 then 'No'
end;
Remake you two CASE clauses to a single CASE clause following this pattern.
However, you only use CASE when you can not move filters and conditions into standard part of SQL select. Normal approach would be to minimize data that SQL engine has to fetch, using pre-filtering. The CASE uses post-filtering, it makes SQL engine to fetch all the data, regardless if it needs it or not, and then discard the unneeded fetched data. That is redundant work slowing down the process.
In your case you already extracted the condition into WHERE clause, that is good.
SELECT
...
WHERE (keywords.keyword LIKE '%purchased%')
OR (keywords.keyword LIKE '%item%')
Since you pre-filter your data stream to always contain "item" or "purchase" then the CASE clause of yours would always return 1 on all rows selected under this WHERE pre-filtering. Hence - just remove the redundant CASE clause and put "1" instead.
SELECT Count(1)
FROM products
LEFT JOIN keywords_products ON products.product_rec_id = keywords_products.product_rec_id
LEFT JOIN keywords ON keywords_products.keyword_rec_id = keywords.keyword_rec_id
WHERE (keywords.keyword LIKE '%purchased%')
OR (keywords.keyword LIKE '%item%')
Now, given that WHERE clause is processed logically after JOINing, this your query de facto transformed LEFT JOINs into FULL JOINs ( your WHERE clause just discards rows with NULL "keyword" column values ) but aghain in unreliable and inefficient method. Since you do not want to have "keyword is NULL" kind of rows anyway - just convert your left joins to normal joins.

Recursive SQLite CTE with JSON1 json_each

I have a SQLite table where one column contains a JSON array containing 0 or more values. Something like this:
id|values
0 |[1,2,3]
1 |[]
2 |[2,3,4]
3 |[2]
What I want to do is "unfold" this into a list of all distinct values contained within the arrays of that column.
To start, I am using the JSON1 extension's json_each function to extract a table of values from a row:
SELECT
value
FROM
json_each(
(
SELECT
values
FROM
my_table
WHERE
id == 2
)
)
Where I can vary the id (2, above) to select any row in the table.
Now, I am trying to wrap this in a recursive CTE so that I can apply it to each row across the entire table and union the results. As a first step I replicated (roughly) the results from above as follows:
WITH RECURSIVE result AS (
SELECT null
UNION ALL
SELECT
value
FROM
json_each(
(
SELECT
values
FROM
my_table
WHERE
id == 2
)
)
)
SELECT * FROM result;
As the next step I had originally planned to make id a variable and increment it (in a similar manner to the first example in the documentation, but haven't been able to get that to work.
I have gone through the other examples in the documentation, but they are somewhat more complex and I haven't been able to distill those down to see how they might apply to this problem.
Can someone provide a simple example of how to solve this (or a similar problem) with a recursive CTE?
Of course, my goal is to solve the problem with or without CTEs so Im also happy to hear if there is a better way...
You do not need a recursive CTE for this.
To call json_each for multiple source rows, use a join:
SELECT t1.id, t2.value
FROM my_table AS t1
JOIN json_each((SELECT "values" FROM my_table WHERE id = t1.id)) AS t2;

Using the SQLite LIKE clause

Kindly review this simple SQLite-fiddle .
If any word in the column ITEM of table TWO matches any word in the column NAME_2 of table ONE, there should be a result(s).
Tried many permutes, yet not sure how to form the query for achieving this. Should the GLOBclause be used instead of LIKE, or perhaps some other wildcard patterns?
Many thanks in advance!
As per my comment, I think you can make use of instr as well. For example:
SELECT * FROM Table1 T1, Table2 T2 where instr(T2.NAME_2,T1.ITEM);
The above should return rows where T2.NAME contains a string = T1.ITEM

How can I join and also exclude on two fields in Access?

I need some guidance about making two different but related queries in Access:
Query 1: Table 1 joins on matches in Table 2 using two fields and using OR (i.e. can match on one field or the other).
Query 2: Table 1 joins on non-matches (excludes) in Table 2 using two fields and using OR (i.e. can match on one field or the other)
1: note the parenthesis (you could also do this in join but my preference is in the where statement) This is approximate code, the syntax may be slightly off for Access SQL but it should help point you in the right direction.
WHERE ((table1.fieldA = table2.fieldB
AND table1.fieldA = table2.fieldC) OR
table1.fieldA = table2.fieldD)
2:
FROM table1
LEFT JOIN Table2
ON (table1.fieldA = table2.fieldB
AND table1.fieldA = table2.fieldC)
OR table1.fieldA = table2.fieldD
WHERE (IS NULL table2.fieldB AND
IS NULL table2.fieldC)
OR IS NULL table2.fieldD

Resources