Extract all except part of the END of the string using PostgreSQL - sql

I have records in a Postgres database table in which I have extraneous data in a particular column. I want to select everything except that piece of text from that column. That piece of text is at the end of the data in the column. If that text appears before or in the middle of the product_name, it should not be removed.
How can I compose the select statement? Below is the data and I want to remove the word 'test2' from the result set.
id|product_name |owner
---------------------
12|sissors test2 |23
13|Sample test2 |43
14|test2scoop test2 |43

Something like following should work:
SELECT id, replace(product_name, 'test3', '') AS product_name, owner FROM ...

What does the PostgreSQL manual section on string functions suggest to you?
regexp_replace(string text, pattern text, replacement text [, flags text])
Replace substring(s) matching a POSIX regular expression. See Section 9.7.3 for more information.
regexp_replace('Thomas', '.[mN]a.', 'M')
Hence:
SELECT id, regex_replace(product_name, 'test3', '') AS product_name, owner
FROM data -- since the table is anonymous in the question
And that's the complicated one — there's also replace for straight-text mapping (a little further through the list of functions on the manual page), which would suffice for the task on hand.
SELECT id, replace(product_name, 'test3', '') AS product_name, owner
FROM data -- since the table is anonymous in the question

I'm just guessing about what you want, but perhaps this will do:
select id
, replace(product_name,' test2,'') as product_name
, owner
from my_table
I'm also guessing that you meant "test2" instead of "test3".
Also note I'm showing a leading blank in the search string. That's based on the example data provided.

Related

How to search for a string in a CLOB and display the value after it in Oracle SQL?

I need to do this within one query, I am not sure if it is possible. I have a table called STORE_VALUES with columns CODE and VALUE. CODE is the PKEY of this table. VALUE is a CLOB column containing a large XML object
CODE
VALUE
DataSet1
....some xml... <Version>1</Version>...some more xml
DataSet2
....some xml... <Version>5</Version>...some more xml
I need to look for the first instance of the tag <Version> and show the number after it (There is more than one instance but I only care about the first)
I believe I need to use dbms_lob.instr but I can't figure out how to do that. Any help is appreciated, thanks!
This is what I have tried so far but it is only showing me whatever is after that value I need (So it displays </Version> followed by the rest of the clob)
SELECT code, dbms_lob.substr(VALUE, dbms_lob.instr(VALUE,'<Version>'),dbms_lob.INSTR(VALUE,'</Version>' )) from STORE_VALUES;
Using the limited information you provided I created a sample table with some sample data. The one caveat that you must remember here is that you have to traverse the xml. Since I only have 'Version' in the CLOB column, I only needed to use Version in my query below. However, if it had a parent element like for example Versions than I would have to adjust my query to do something like '/Versions/Version' in order to get to that element in the xml.
--table ddl
CREATE TABLE STORE_VALUES
( CODE VARCHAR2(20),
VALUE CLOB
) ;
-- potential insert statement. --
INSERT INTO STORE_VALUES (CODE, VALUE) VALUES ('1', '<Version>1</Version>');
INSERT INTO STORE_VALUES (CODE, VALUE) VALUES ('2', '<Version>5</Version>');
--possible query dependent on full xml
SELECT
extractvalue(
xmltype(
dbms_lob.substr(
value, 3000
)
), 'Version'
) version_el
FROM
store_values;
Since your VALUE column is XML, you could try using the XML functions available to extract the value. The actual XPath to extract the "Version" from the XML may vary depending on how your XML document is structured.
Query
WITH
store_values (code, VALUE)
AS
(SELECT 'DataSet1',
TO_CLOB ('<doc><attr1>abc</attr1><Version>1</Version><attr2>def</attr2></doc>')
FROM DUAL
UNION ALL
SELECT 'DataSet2',
TO_CLOB ('<doc><attr1>ghi</attr1><Version>5</Version><attr2>jkl</attr2></doc>')
FROM DUAL)
SELECT code, EXTRACTVALUE (xmltype (VALUE), '/doc/Version/text()') AS version_no
FROM store_values;
Result
CODE VERSION_NO
___________ _____________
DataSet1 1
DataSet2 5
Update
Since the VALUE column does not contain true XML, you can extract the the value using REGEX expressions. The query below will give the same result as above.
WITH
store_values (code, VALUE)
AS
(SELECT 'DataSet1',
TO_CLOB ('<doc><attr1>abc</attr1><Version>1</Version><attr2>def</attr2></doc>')
FROM DUAL
UNION ALL
SELECT 'DataSet2',
TO_CLOB ('<doc><attr1>ghi</attr1><Version>5</Version><attr2>jkl</attr2></doc>')
FROM DUAL)
SELECT code,
REGEXP_REPLACE (REGEXP_SUBSTR (VALUE, '<Version>.*</Version>'), '<[^>]*>') AS version_no
FROM store_values;

sql query with multiple partial match condition

i have a table column looks like below.
what is the sql query statement i can use to have multiple partial match conditions?
search by ID or Name
if search abc then list the row A1 , row A2
if search test then list the row A1 , row A2, row 3
if search ghj then list the row A2
i was trying this but nothing return:
SELECT * FROM table where colB LIKE '"ID":"%abc%"'
updating data in text
{"ItemId":"123","IDs":[{"ID":"abc","CodingSystem":"cs1"}],"Name":"test itemgh"}
{"ItemId":"123","IDs":[{"ID":"ghj","CodingSystem":"cs1"}],"Name":"test abc"}
{"ItemId":"123","IDs":[{"ID":"defg","CodingSystem":"cs1"}],"Name":"test 111"}
JSON parsing
Oracle
Looked into the JSON parsing capabilities of Oracle and I managed to make running a query like this:
select * from table t where json_exists(t.colB, '$.IDs[?(#.ID=="abc")]') or json_exists(t.colB, '$.IDs?(#.name=="abc"')
And inside the same JSON query expression:
select * from table t where json_exists(t.colB, '$.IDs[?(#.ID=="abc" || #.name=="abc")]')
The call of function json_exists() is the key to this.
The first parameter can be a VARCHAR2, and I also tried with a BLOB containing text, and it works.
The second parameter is the path to your json object attribute that needs to be tested, with the condition.
I wrote two ORed conditions for the ID and for the Name, but maybe there is a better JSON query expression you can use to include them both.
More information about json_exists() function here.
Postgres
There is a JSON datatype in Postgres that supports parsing in queries.
So, if your colB column is declared as JSON you can do something like this:
select * from table where colB->>'Name' LIKE '%abc%';
And in order to have available the array elements of the IDs array, you should use the function json_array_elements().
select * from table, json_array_elements(colB->'IDs') e where colB->>'Name' LIKE '%abc%' or e->>'ID' = 'abc';
Check an example I created for you here.
Here is an online tool for online testing your JSON queries.
Check also this question in SO.
MSSQL Server 2017
I made a couple of tests also with MS SQL Server, and I managed to create an example searching for partial matching in the name field.
select * from table where JSON_VALUE(colB,'$.Name') LIKE '%abc%';
And finally I arrived to a working query that does partial match to the Name field and full match to the ID field like this:
select * from table t
CROSS APPLY OPENJSON(colB, '$.IDs') WITH (
ID VARCHAR(10),
CodingSystem VARCHAR(10)
) e
where JSON_VALUE(t.colB,'$.Name') LIKE '%abc%'
or e.ID = 'abc';
The problem is that we need to open the IDs array, and make something like a table from it, that can be queried also by accessing its columns.
The example I created is here.
LIKE text query
Your tries are good but you misplace the % symbols. They have to be first and last in your given string:
If you want the ID to be the given value:
SELECT * FROM table where colB LIKE '%"ID":"abc"%'
If the given value can be anywhere, then don't put the "ID" part:
SELECT * FROM table where colB LIKE '%abc%'
If the given value can be only on the ID or Name field then:
SELECT * FROM table where colB LIKE '%"ID":"abc"%' OR colB LIKE '%"Name":"abc"%'
And because you are giving hard-coded identifiers of fields (eg ID and Name) that can be in variable case:
SELECT * FROM table where lower(colB) LIKE '%"id":"abc"%' OR lower(colB) LIKE '%"name":"abc"%'
Assuming that the number of spaces do not vary between the : character and the value or the name of the properties.
For partial matching you can use more % in between like '%"name":"%abc%"%':
SELECT * FROM table where lower(colB) LIKE '%"id":"abc"%' OR lower(colB) LIKE '%"name":"%abc%"%'
Regular Expressions
A different option would be to test with regular expressions.
Consider checking this: Oracle extract json fields using regular expression with oracle regexp_substr

postgresql - check if a row contains a string without considering spaces

Is it possible to check if a row contains a string without conisdering spaces?
Suppose I have a table like the one above. I want to know if the query column contains a string that may have different consecutive number of space than the one stored or vice versa?
For example: the first row's query is select id, username from postgresql, and the one I want to know if stored in the table is:
select id, username
from postgresql
That is to say the one that I want to know if exists in the table is indented differently and hence has different number of space.
You can use REGEXP_REPLACE; this will likely be very slow on large data set.
SELECT * from table
where REGEXP_REPLACE('select id, username from postgresql ', '\s+$', '') = REGEXP_REPLACE(query, '\s+$', '')
I think you would phrase this as:
where $str ~ replace('select id, username from postgresql', ' ', '[\s]+')
Note: This assumes that your string does not have other regular expression special characters.

SQL : Varchar add space to the end of the text

When I add element to column (varchar) I get extra space. For example if I have a table Student with name varchar(10) and I do:
INSERT INTO Student (id,name) VALUES (1,'student')
SELECT name FROM Student WHERE id=1
I get student[space][space][space].
How can I fix without changing the type to text?
Most databases output results from a query in a fixed tabular format. To see where a string really begins and ends, you need to concatenate another character. Here are three ways, depending on the database:
select '"'+name+'"'
select '"'||name||'"'
select concat('"', name, '"')
You'll probably find that the spaces are an artifact of the query tool.

What is the difference in [ ] and ( ) in SQL?

I've seen both used but I can't seem to understand when to use each?
To me is seems like you enter the name of the table you are referring from in the ( ) and the field name in the [ ]?
Could anyone explain?
The square brackets are used In Microsoft products to specify that what's within them is an identifier (the standard quoted identifiers are double quotes " ", which Microsoft SQL Sever also supports). This is used when you have a database name, user name, table name, field name, view name, procedure name (et.c.) that happens to be the same as a keyword, or contains characters that would break the syntax. This is often used in generated code to safeguard against identifiers that can't otherwise be used in the code. A generated query could look like this:
select [Id], [Name], [Password hint]
from [dbo].[MyDataBase].[User]
Here the field name Password hint would break the syntax if used without brackets, and the table name User could conflict with the keyword User.
Parentheses are used to group items, for example as part of the syntax of some clauses, for example an insert:
insert into someTable (field1, field2) values ('value1', 'value2')
They can also be used in expressions:
select Price * (Quantity + FreeItems) from Articles
They can also be used around queries to make subqueries:
select o.Name
from (select Name, Age from Persons where City = 'Oslo') as o
where o.Age > 18
() are used for passing parameters to functions and stored proceedures etc. [] are used to encapsulate field name (etc.) which include punctuation (spaces and special characters as per the comment above). [] are useful sometimes to name fields for display
SELECT FFgg AS [Some field discription] FROM table1;
Hope this helps.