SQL Server - conditionally delete part of a string within a field - sql-server

I checked both of these:
Delete part of a field in SQL
Deleting part of a string in MYSQL
but they're not quite what I need.
I've unfortunately inherited a table with a field full of comma-separated strings with no regard for format or order. It's ugly. Now I need to get rid of a particular part of a string:
So let's say I have a table as such:
Column1 Column2
1 XRR01,MMEX1,XFR44
2 XRR02,MMEX1
3 MMEX1,GH345,XFR45,CFA34
4 NMM22,MMEX1,XFR44
5 MMEX1
6 XFR55
I want to do an UPDATE to find and delete any instances of MMEX1 from the Column2 field, and keep the other parts intact.
So then I would be left with:
Column1 Column2
1 XRR01,XFR44
2 XRR02
3 GH345,XFR45,CFA34
4 NMM22,XFR44
5 NULL (or blank, doesn't really matter)
6 XFR55
Is this possible?

Here is one way using Replace function
select replace(replace(Column2,',MMEX1',''),'MMEX1,','')
from Yourtable
replace(Column2,',MMEX1','') will remove the string in middle and last
replace(Column2,'MMEX1,','') will remove the string at the start
Note : storing comma sepearated value in a column is always a pain when comes to data processing. Try and change the table structure

Related

Copy data from one table to another with an array of structs in BigQuery

We are trying to copy data from one table to another using an INSERT INTO ... SELECT statement.
Our original table schema is as follows, with several columns including a repeated record containing 5 structs of various data types:
original table schema
We want an exact copy of this table, plus 3 new regular columns, so made an empty table with the new schema. However when using the following code the input table ends up with fewer rows overall than the original table.
insert into input_table
select column1, column2, null as newcolumn1, null as newcolumn2, null as newcolumn3,
array_agg(struct (arr.struct1, arr.struct2, arr.struct3, arr.struct4, arr.struct5)) as arrayname, column3
from original_table, unnest(arrayname) as arr
group by column1, column2, column3;
We tried the solution from this page: How to copy data from one table into another table which has a record repeated column in GCP Bigquery
but the query would error as it would treat the 5 structs within the array as arrays themselves (data type = eg. string, mode = repeated, rather than nullable/required).
The error we see says that our repeated record column "has type ARRAY<STRUCT<struct1name ARRAY, struct2name ARRAY, struct3name ARRAY, ...>> which cannot be inserted into column summary, which has type ARRAY<STRUCT<struct1name STRING, struct2name STRING, struct3name STRING, ...>> at [4:1]"
Additionally, a query to find rows that exist in the original but not in the input table returns no results.
We also need the columns in this order (cannot do a simple copy of the table and add the 3 new columns at the end).
Why are we losing rows when using the above code to do an insert into... select?
Is there a way to copy over the data in this way and retain the exact number of rows?

Filtering SQL rows based on certain alphabets combination

I have a column that store user input text field from a frontend website. User can input any kind of text in it, but they will also put in a specific alphabets combination to represent a job type - for example 'dri'. As an example:
Row 1: P49384; Open vehicle bonnet-BO-dri 22/10
Row 2: P93818; Vehicle exhaust-BO 10/20
Row 3: P1933; battery dri-pu-103/2
Row 4: P3193; screwdriver-pu 423
Row 5: X939; seats bo
Row 6: P9381-vehicle-pu-bo dri
In this case, I will like to filter only rows that contain dri. From the example, you can see the text can be in any order (user behaviour, they will key whatever they like without following any kind of format). But the constant is that for a particular job type, they will put in dri.
I know that I can simply use LIKE in SQL Server to get these rows. Unfortunately, row 4 is included inside when I use this operator. This is because screwdriver contains dri.
Is there any way in SQL Server I can do to strictly only obtain rows that has dri job type, while excluding words like screwdriver?
I tried to use PATINDEX but it failed too - PATINDEX('%[d][r][i]%', column) > 0
Thanks in advance.
Your data is the problem here. Unfortunately even for denormalised data it doesn't appear to have a reliable/defined format, making parsing your data in a language like T-SQL next to impossible. What problems are there? Based on the original sample data, at a glance the following problems exist:
The first data value's delimiter isn't consistent. Rows 1-5 use a semicolon (;), but row 6 uses a hyphen (-)
The last data value's delimiter isn't consistent. Row 1, 2 & 4 use a space ( ), but row 3 uses a hyphen (-).
Internal data doesn't use a consistent delimiter. For example:
Row 1 has a the value Open vehicle bonnet-BO-dri, which appears to be the values Open vehicle bonnet, BO and dri; so the hyphen(-) is the delimiter.
Row 5 has seats bo, which appears to be the values seats and bo, so uses a space ( ) as a delimiter.
The fact that row 6 has vehicle as its own value (vehicle-pu-bo-dri), however, implies that Open vehicle bonnet and Vehicle Exhaust (on rows 1 and 2 respectively) could actually be the values Open, vehicle, & bonnet and Vehicle & Exhaust respectively.
Honestly, the solution is to fix your design. As such, your tables should likely look something like this:
CREATE TABLE dbo.Job (JobID varchar(6) CONSTRAINT PK_JobID PRIMARY KEY NONCLUSTERED, --NONCLUSTERED Because it's not always ascending
YourNumericalLikeValue varchar(5) NULL); --Obviously use a better name
CREATE TABLE dbo.JobTypeCompleted(JobTypeID int IDENTITY (1,1) CONSTRAINT PK_JobTypeID PRIMARY KEY CLUSTERED,
JobID varchar(6) NOT NULL CONSTRAINT FK_JobType_Job FOREIGN KEY REFERENCES dbo.Job (JobID),
JobType varchar(30) NOT NULL); --Must likely this'll actually be a foreign key to an actual job type table
GO
Then, for a couple of your rows, the data would be inserted like so:
INSERT INTO dbo.Job (JobID, YourNumericalLikeValue)
VALUES('P49384','22/10'),
('P9381',NULL);
GO
INSERT INTO dbo.JobTypeCompleted(JobID,JobType)
VALUES('P49384','Open vehicle bonnet'),
('P49384','BO'),
('P49384','dri'),
('P9381','vehicle'),
('P9381','pu'),
('P9381','bo'),
('P9381','dri');
Then you can easily get the jobs you want with a simple query:
SELECT J.JobID,
J.YourNumericalLikeValue
FROM dbo.Job J
WHERE EXISTS (SELECT 1
FROM dbo.JobTypeCompleted JTC
WHERE JTC.JobID = J.JobID
AND JTC.JobType = 'dri');
You can apply like operator in your query as column_name like '%-dri'. It means find out records that end with "-dri"

Fetching results from inner query having comma separated values - SQL Server

I have a temp table having two columns - key and value:
temp_tbl:
key value
---|-----
k1 | a','b
Below is the insert script with which I am storing the value in temp_tbl:
insert into temp_tbl values ('k1', 'a'+char(39)+char(44)+char(39)+'b');
Now, I want trying to fetch records from another table (actual_tbl) like this:
select * from actual_tbl where field_value in
(select value from tamp_tbl where key = 'k1');--query 1
But this is not returning anything.
I want the above query to behave like the following one:
select * from actual_tbl where field_value in
('a','b');--query 2
Where am I doing wrong in query 1?
I am using sql server.
Where am I doing wrong in query 1?
Where you are going wrong is in failing to understand the way the IN keyword works with a subquery vs a hard-coded list.
When an IN clause is followed by a list, each item in the list is a discrete value:
IN ('I am a value', 'I am another value', 'I am yet another value')
When it's followed by a sub-query, each row generates a single value. Your temp table only has one row, so the IN clause is only considering a single value. No matter how you try to "trick" the parser with commas and single-quotes, it won't work. The SQL Server parser is too smart to be tricked. It will know that a single value of 'a','b' is still just a single value, and it will look for that single value. It won't treat them as two separate values like you are trying to do.

How to configure a table column in TSQL that works as a sequence depending on the values of another two columns?

I have a table that looks like this:
ID A B Count
-----------------
1 abc 0 1
2 abc 0 2
3 abc 1 1
4 xyz 1 1
5 xyz 1 2
6 xyz 1 3
7 abc 1 2
8 abc 0 3
The "Count" column is incremented by one in the next insertion depending on the value of fields "A" and "B". so for example, if the next record I want to insert is:
ID A B Count
-----------------
abc 0
The value of count will be 4.
I have been trying to find documentation about this, but I'm still quite lost in the MS SQL world! There must be a way to configure the "Count" column as a sequence dependent on the other two columns. My alternative would be to select all the records with A=abc and B=0, get the maximum "Count", and do +1 in the latest one, but I suspect there must be another way related to properly defining the Count column when creating the table.
The first question is: Why do you need this?
There is ROW_NUMBER() which will - provided the correct PARTITION BY in the OVER() clause - do this for you:
DECLARE #tbl TABLE(ID INT,A VARCHAR(10),B INT);
INSERT INTO #tbl VALUES
(1,'abc',0)
,(2,'abc',0)
,(3,'abc',1)
,(4,'xyz',1)
,(5,'xyz',1)
,(6,'xyz',1)
,(7,'abc',1)
,(8,'abc',0);
SELECT *
,ROW_NUMBER() OVER(PARTITION BY A,B ORDER BY ID)
FROM #tbl
ORDER BY ID;
The problem is: What happens if a row is changed or deleted?
If you write this values into a persistant column and one row is removed physically, you'll have a gap. Okay, one can live with this... But if a value in A is changed from abc to xyz (same applies to B of course) the whole approach breaks.
If you still want to write this into a column you can use the ROW_NUMBER() from above to fill these values initially and a TRIGGER to set the next value with your SELECT MAX()+1 approach for new rows.
If the set of combinations is limited you might create a SEQUENCE (needs v2012+) for each.
But - to be honest - the whole issue smells a bit.

query with string manipulations

I need a query for the following problem. Table1 specifies the mandatory input fields. I will fetch the fields with inactive = 'No' and mandt field = 'yes'
So i have 4 records with fields as sev,sev1,cde,frt.
Table1:
Fields Inactive mandt_field
sev no yes
sev1 no yes
sev2 yes yes
abd no no
cde no yes
frt no yes
Table 2 has data similar to this
concession add_fields
TH-123 -sev*yes-sev1*no-sev2*yes
Th-234 -sev*yes-sev1*yes-cde*yes-frt*no
Th-345 -sev*yes-cde*yes-frt*no
TH-456 -cde*no-frt*no
Th-012 -sev*no-sev1*no-cde*no-frt*no
Th-451 -frt*yes
TH-900 -sev2*no
Now i need records which does not have the above 4 fields in add_fields.
output should return the following records :- TH-123,Th-345,TH-456,Th-451,TH-900.
These 4 records does not have all 4 fields that we have retrieved from the previous table (sev,sev1,cde,frt).
The no. of the fields resulting from table1 may vary..As these are from a table data...so we may have (sev,sev1,cde,frt....)
To answer your original question
SELECT DISTINCT concession
FROM Table2
INNER JOIN Table1 ON Table2.add_fields NOT LIKE '%-' + Table1.Fields + '*%'
WHERE Inactive='no' AND mandt_field='yes'
Following on from the comments though add_fields seems to contain a list of items. That in turn contains pairs of codes and yes/no values. I suggest restructuring your table2 as follows. This will put it into first normal form.
Putting it into first normal form will make updates, and searches easier without having to parse every string each time to break it into its constituent items. It will also allow you to apply integrity constraints to your data.
concession code YesNo
----------------------------
TH-123 sev yes
TH-123 sev1 no
TH-123 sev2 yes
Th-234 sev yes
....
Short answer: Probably but you don't want to try.
Instead, create a third table from table two which contains the same data but in a form which you can use. This means to split the field add_fields into columns so you can use a join against table Table1
Long answer: SQL is touring complete, so you can write any program in it (mandelbrot set in T-SQL). But that gets complex quickly, so you really don't want to do it.

Resources