SQL removing part of delimited field based on joining match? - sql

Maybe there is a better method before I get to this step, but is there an easy way to match on one field, if it matches remove part of the match from a string in a second field.
TABLE example
ID | ID LIST
-----|---------
ID07 |ID05;ID06;ID07;ID08
This is just a one record example so ID and ID LIST will vary.
I'm looking to join and update/ replace the "nothing" or perhaps add a value to remove later.
Result I'm looking for
ID | ID LIST
-----|---------
ID07 |ID05;ID06;ID08
Is there any easy way to do this or should I go about this another way? I know some people would use a WHERE IN, but ID is going to vary. Maybe WHERE IN that field name. I'm a little confused conceptualizing this.
I'm using SQL Server MGMT studio.

You can use replace function .. if id is in id_list is replaced with empty string
select replace(ID_LIST, ID +';', '')
from your_table;

UPDATE TABLE
SET ID_LIST = CASE WHEN ID_LIST = ID THEN ''
WHEN ID_LIST LIKE ID + ';%' THEN SUBSTRING(ID_LIST, LEN(ID)+1, LEN(ID_LIST)-LEN(ID)-1)
WHEN ID_LIST LIKE '%;' + ID THEN LEFT(ID_LIST, LEN(ID_LIST)-LEN(ID)-1)
ELSE REPLACE(ID_LIST, ';'+ID+';', ';')
END
WHERE ';'+ID_LIST+';' LIKE '%;'+ID+';%'

Related

How to get the data in SQL Server for string concat value compare to int value without using like operator

I have table with data like this:
Id | StringValue
----+-------------
1 | 4,50
2 | 90,40
I will get input StringValue like 4. I need to fetch the data exact matched record. When I am using LIKE operator, select query is returning two rows, but I need exact matched data record only.
Can anybody please help me with this?
SELECT *
FROM Table1
WHERE StringValue like '%4%'
But that returns two rows - both ID 1 and 2.
My expectation is I need to get ID = 1 row only
Storing delimited data like this is a well documented anti-pattern, violates basic normalisation principles and prevents the database engine from fully utilising an index.
What you can do is delimit your search value and also ensure the expression to search is correctly delimited; this is an unsargable expression however and the strorage engine will have to scan all rows every time -
declare #valueToFind varchar(10) = '4';
select *
from t
where Concat(',', t.StringValue, ',') like Concat('%,' #valueToFind, ',%');
for SQL Server 2016 and later you can use STRING_SPLIT or earlier version of SQL Server, there are many alternative, just do a search for it.
Or, you can simply do
SELECT * FROM Table1 where ',' + StringValue + ',' like '%,4,%'

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

Delete statement does not execute in sql

I read the similar issue shared on stack overflow regarding DELETE command is not execute a query.
I am a beginner level on SQL and was trying to understand identity column action so I created a super basic studentinfo table and put firstname, lastname, and id columns.
ID selected as identity column and incremental is setup 5. That is the summary of the table. And created couple rows for the table.
Now when I execute DELETE FROM StudentInfo WHERE StudentId like '0213422' returns 0 rows affected and of course not deleting that row.
Anyone tell why is that happening?
Thanks in advance
You can either use:
where StudentId like '%0213422%'
or
where StudentId = '0213422'
Like can be used with placeholders like '%' or '_'
'%' - indicates that there could be multiple characters in the placeholder.
'_' - indicates that there is exactly one character as a placeholder
ID | Stuff
1 | Foobar
2 | Fobar
where Stuff like 'F%bar' --would return both row
where Stuff like 'F_bar' --would retun only the second row
Normally an identity column is type bigint or int and contains simply spoken just numbers. So I wonder that a value can have a leading 0.
I suggest to use a select statement first to see, what is in the result set like
Select * FROM Studentinfo WHERE StudentId like '%213422'
or
Select * FROM Studentinfo WHERE StudentId >=213422

update a column using values from a different column of the same table

Given the DB table:
CREATE TABLE stuff (
id text not null,
other text
);
That has lots of id values but has all other set to NULL, is there an elegant way to update the table so that all other rows get updated to OTHER-{id} (where {id} is the value of the id column)?
(It must work in Postgresql)
Only a simple update statement is needed with some string concatenation (||):
update stuff
set other = 'OTHER-' || id
You'll want to use the following:
UPDATE stuff
SET other = 'OTHER-' || id;
UPDATE is the keyword used to identify which table you'd like to update.
SET is the keyword used to identify which column you'd like to update, and this is where you choose to assign the column to:
'OTHER-' || id
'OTHER-' being a string
|| a shorthand way to concatenate
id the value you want.
Another way of writing this would be
other = concat('OTHER-',id);
I along with many others will find the || method to be much cleaner, but it's worth knowing about the dedicated function as well.

SQL WHERE is anything

I'm working on a database query via a search bar and would like it to sometimes yield all results (depending on what is inputted)
I know that for SELECT you can use * in order to select all columns. Is there similar SQL syntax: i.e. WHERE name IS * to essentially always be true?
Edit to clarify:
The nature of the clause is that a variable is used to set the name (I'm actually not able to change the clause, that was made clear). i.e. WHERE name IS [[inputName]] (inputName is the decided by the search bar)
WHERE ISNULL(name, '') = ISNULL(name, '')
(assuming that 'name' is of a string type)
Just make the column reference itself. However, if this is the only goal of your query, why are you against omitting the WHERE clause?
If you want to return all results in a SQL statement, you can simply omit the WHERE clause:
SELECT <* or field names> FROM <table>;
You should use WHERE only when you want to filter your data on a certain field. In your case you just don't want to filter at all.
Actually you don't need WHERE clause at all in this situation. But if you insist then you should write your predicate so it always returns true. This can be done many ways:
Any predicate like:
WHERE 1=1
With column:
WHERE name = name OR name is null
With LIKE:
WHERE name LIKE '%' OR name is null
With passed parameter:
WHERE name = #name OR #name is null
You can think of more of course. But I think you need the last one. Pass NULL from app layer if you want all rows.