When we do data refresh we need to append \\prod01\\Test\Load server name with \\prod01.qa.com\\Test\Load
How do I write update query for this. There can be different server names all I need to do is write update script to append server name with qa.com
This is my query that gives all results that have server location.
select * from AppSetting where Value like '%\\%\%' or Value like '%//%/%';
My Prod data looks like this
Value
\\prod01\Images\Load
\\prod01prod6253\Images\Load
\\server05ser\Images\Delete
\\pgdg1076\Email
\\pgdg1076ythg\Test\Load
http://prod7/delta/
My QA data should looks like this after update query
Value
\\prod01.qa.com\Images\Load
\\prod01prod6253.qa.com\Images\Load
\\server05ser.qa.com\Images\Delete
\\pgdg1076.qa.com\Email
\\pgdg1076ythg.qa.com\Test\Load
http://prod7.qa.com/delta/
This is the update query I have. Can I write a generic query
UPDATE eroom.AppSetting
SET Location = REPLACE(Location, '\\prod01\', '\\prod01.qa.tbc.com\')
WHERE Location like '%\\prod01\%';
UPDATE eroom.AppSetting
SET Location = REPLACE(Location, '\\server05ser\', '\\server05ser.qa.tbc.com\')
WHERE Location like '%\\server05ser\%';
I'm posting this as a new answer, as the OP moved the goal posts quite a bit. Instead, I now use CHARINDEX to find the location of each slash (forward or back). As fortunately the injection needs to happen before the 3rd slash, we can use that to our advantage:
SELECT STUFF(V.Value,CI3.I,0,'.qa.tbc.com') AS NewValue,*
FROM (VALUES('\\prod01\Images\Load'),
('\\prod01prod6253\Images\Load'),
('\\server05ser\Images\Delete'),
('\\pgdg1076\Email'),
('\\pgdg1076ythg\Test\Load'),
('http://prod7/delta/'))V([value])
CROSS APPLY (VALUES(CASE WHEN V.[value] LIKE '%/%' THEN '/' ELSE '\' END)) L(C) --So I don't have to keep checking what character I need
CROSS APPLY (VALUES(CHARINDEX(L.C,V.[value]))) CI1(I)
CROSS APPLY (VALUES(CHARINDEX(L.C,V.[value],CI1.I+1))) CI2(I)
CROSS APPLY (VALUES(CHARINDEX(L.C,V.[value],CI2.I+1))) CI3(I);
This is one method. I put the expressions for the PATINDEX and CHARINDEX in the FROM, as I find it far easier to read, and means less repetition:
SELECT V.[value],
ISNULL(STUFF(V.Value,ISNULL(CI.fs,CI.bs),0,'.qa.tbc.com'),V.[value]) AS NewValue
FROM (VALUES('\\prod01\Images\Load'),
('\\prod05\Images\Delete'),
('\\prod10\Email'),
('//http://prod7/delta/'))V([value])
CROSS APPLY (VALUES(NULLIF(PATINDEX('%prod[0-9]%',V.value),0)))PI(I)
CROSS APPLY (VALUES(NULLIF(CHARINDEX('/',V.[value],PI.I),0),NULLIF(CHARINDEX('\',V.[value],PI.I),0))) CI(fs,bs);
This answers the original version of the question.
The simplest way might be with stuff() and a case expression:
select (case when location like '\\prod[0-9][0-9]\*'
then stuff(location, 9, 0, '.qa.tbc.com'
else location
end)
The "prod" portion looks to be fixed length, so you don't need to search for a pattern.
Related
I am trying to filter part of a string until it reaches a specific character and repeat until the end of string.
Data loooks like
095930
CF0010+EN
060983+PS
086588+GG;086326+GG
900010;
CF0002;;CF0018;
Output should be
095930
CF0010
060983
086588;086326
900010;
CF0002;;CF0018;
I tried the following:
SUBSTRING(column, 1, CHARINDEX('+',column+ '+', 1)-1)
But this removes everything after the + which is not what I need.
Removing everything after and including a character in a value is quite simple, just use LEFT and CHARINDEX:
LEFT(DS.Item,CHARINDEX('+',DS.Item + '+')-1)
The real problem you have is a little more complex:
You have a denormalised design, making this far more difficult.
You want to retain the denormalised design in the results, making this difficult again
You are using a version of SQL Server that is very close to end of support that has no in built support for string splitting and aggregation.
Saying that, unless you were using Azure SQL Database (or somehow had a copy of SQL Server 2022) I wouldn't suggest STRING_SPLIT, as it doesn't provide an ordinal position parameter. Though STRING_AGG would make things far easier; and you could use a JSON splitter too.
Instead I use DelimitedSplit8K_LEAD here, and then "Ye Olde FOR XML PATHe (and STUFF)" for the string aggregation. This gives this clunky solution:
SELECT *
INTO dbo.YourTable
FROM (VALUES('095930'),
('CF0010+EN'),
('060983+PS'),
('086588+GG;086326+GG'),
('900010;'),
('CF0002;;CF0018;'))V(YourString);
GO
SELECT YT.YourString,
STUFF((SELECT ';' + LEFT(DS.Item,CHARINDEX('+',DS.Item + '+')-1)
FROM dbo.DelimitedSplit8K_LEAD(YT.YourString,';') DS
ORDER BY DS.ItemNumber
FOR XML PATH(''),TYPE).value('(./text())[1]','varchar(8000)'),1,1,'') AS NewString
FROM dbo.YourTable YT;
GO
DROP TABLE dbo.YourTable;
If you were using Azure SQL Database (or SQL Server 2022) then the answer would be much simpler:
SELECT YT.YourString,
STRING_AGG(LEFT(SS.Value,CHARINDEX('+',SS.Value + '+')-1),';') WITHIN GROUP (ORDER BY SS.Ordinal) AS NewString
FROM dbo.YourTable YT
CROSS APPLY STRING_SPLIT(YT.YourString,';',1) SS
GROUP BY YT.YourString; --Assuming YourString has a unique value
EDIT: I made a mistake and answered this pertaining to SSIS and answered as if you were loading this data originally. I am leaving it though because SSIS is a complimentary tool of SQL Server.
To do what you ask...
Script Component:
var firstSplit = Row.[your Column].Split(';');
List<string> formatedCols = new List<string>();
foreach(var col in firstSplit)
formatedCols.Add(col.Split('+')[0]);
Row.[Output Column Name] = string.Join(";", formatedCols.ToArray());
I would recommend a child table though with a 1 to many relationship to parent.
I am trying to query a JSON column that has mixed capitalization. For instance, some rows have keys that are all lower case like below:
{"name":"Screening 1","type":"template","pages":[{"pageNumber":1,...}
However, some of the rows have keys that are capitalized on its first letter like this:
{"Type":"template","Name":"Screening2","Pages":[{"PageNumber":1,...}
Unfortunately, SQL Server seems to only supports JSON path system that is case sensitive. Therefore, I can't query on all rows successfully. If I use lower case path like '$.pages' in a query like below:
SELECT ST.Id AS Screening_Tool_Id
, ST.Name AS Screening_Tool_Name
, ST.Description AS Screening_Tool_Description
, COUNT(JSON_VALUE (SRQuestions.value, '$.id')) AS Question_Specific_Id
FROM dbo.ScreeningTemplate AS ST
CROSS APPLY OPENJSON(ST.Workflow, '$.pages') AS SRPages
CROSS APPLY OPENJSON(SRPages.Value, '$.sections') AS SRSections
I miss any row that has capitalized keys. Is there any way to query all rows ignoring their capitalization?
According to MS, looks like you're stuck with a case-sensitive query:
When OPENJSON parses a JSON array, the function returns the indexes of
the elements in the JSON text as keys.+ The comparison used to match
path steps with the properties of the JSON expression is
case-sensitive and collation-unaware (that is, a BIN2 comparison).
https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql
If the only variations are in the capitalization of the first character, you could try to work around this limitation by creating queries with the variants and UNION the results together.
Maybe you can just lower the json:
COUNT(JSON_VALUE (lower(SRQuestions.value), '$.id')) AS Question_Specific_Id
Old question but I came across this when googling a similar issue so I will chip in with my solution:
SELECT #pb = PB from
OPENJSON(#PropertyBagsAsJson, '$."$values"')
WITH (
PbId1 nvarchar(MAX) 'lax $.Id',
PbId2 nvarchar(MAX) 'lax $.id',
PB nvarchar(MAX) '$' AS JSON
)
WHERE COALESCE(PbId1,PbId2) = #PropertyBagId
I hope that the example is clear. Basically I just add all possible casing of the property and then just use Coalesce to filter the results.
You can use openjson. Instead of
JSON_VALUE (SRQuestions.value, '$.id')
you can write
(select Value
from openjson( SRQuestions.value )
where [Key] collate latin1_general_ci = 'id')
You must use a Case-Insensitive "_ci" collation here. "UTF8_General_CI" works too, as does "database_default" if the database uses a CI collation.
I have a table which has a column with doc locations, such as AA/BB/CC/EE
I am trying to get only one of these parts, lets say just the CC part (which has variable length). Until now I've tried as follows:
SELECT RIGHT(doclocation,CHARINDEX('/',REVERSE(doclocation),0)-1)
FROM Table
WHERE doclocation LIKE '%CC %'
But I'm not getting the expected result
Use PARSENAME function like this,
DECLARE #s VARCHAR(100) = 'AA/BB/CC/EE'
SELECT PARSENAME(replace(#s, '/', '.'), 2)
This is painful to do in SQL Server. One method is a series of string operations. I find this simplest using outer apply (unless I need subqueries for a different reason):
select *
from t outer apply
(select stuff(t.doclocation, 1, patindex('%/%/%', t.doclocation), '') as doclocation2) t2 outer apply
(select left(tt.doclocation2), charindex('/', tt.doclocation2) as cc
) t3;
The PARSENAME function is used to get the specified part of an object name, and should not used for this purpose, as it will only parse strings with max 4 objects (see SQL Server PARSENAME documentation at MSDN)
SQL Server 2016 has a new function STRING_SPLIT, but if you don't use SQL Server 2016 you have to fallback on the solutions described here: How do I split a string so I can access item x?
The question is not clear I guess. Can you please specify which value you need? If you need the values after CC, then you can do the CHARINDEX on "CC". Also the query does not seem correct as the string you provided is "AA/BB/CC/EE" which does not have a space between it, but in the query you are searching for space WHERE doclocation LIKE '%CC %'
SELECT SUBSTRING(doclocation,CHARINDEX('CC',doclocation)+2,LEN(doclocation))
FROM Table
WHERE doclocation LIKE '%CC %'
I have stored values in my database that look like 5XXXXXX, where X can be any digit. In other words, I need to match incoming SQL query strings like 5349878.
Does anyone have an idea how to do it?
I have different cases like XXXX7XX for example, so it has to be generic. I don't care about representing the pattern in a different way inside the SQL Server.
I'm working with c# in .NET.
You can write queries like this in SQL Server:
--each [0-9] matches a single digit, this would match 5xx
SELECT * FROM YourTable WHERE SomeField LIKE '5[0-9][0-9]'
stored value in DB is: 5XXXXXX [where x can be any digit]
You don't mention data types - if numeric, you'll likely have to use CAST/CONVERT to change the data type to [n]varchar.
Use:
WHERE CHARINDEX(column, '5') = 1
AND CHARINDEX(column, '.') = 0 --to stop decimals if needed
AND ISNUMERIC(column) = 1
References:
CHARINDEX
ISNUMERIC
i have also different cases like XXXX7XX for example, so it has to be generic.
Use:
WHERE PATINDEX('%7%', column) = 5
AND CHARINDEX(column, '.') = 0 --to stop decimals if needed
AND ISNUMERIC(column) = 1
References:
PATINDEX
Regex Support
SQL Server 2000+ supports regex, but the catch is you have to create the UDF function in CLR before you have the ability. There are numerous articles providing example code if you google them. Once you have that in place, you can use:
5\d{6} for your first example
\d{4}7\d{2} for your second example
For more info on regular expressions, I highly recommend this website.
Try this
select * from mytable
where p1 not like '%[^0-9]%' and substring(p1,1,1)='5'
Of course, you'll need to adjust the substring value, but the rest should work...
In order to match a digit, you can use [0-9].
So you could use 5[0-9][0-9][0-9][0-9][0-9][0-9] and [0-9][0-9][0-9][0-9]7[0-9][0-9][0-9]. I do this a lot for zip codes.
SQL Wildcards are enough for this purpose. Follow this link: http://www.w3schools.com/SQL/sql_wildcards.asp
you need to use a query like this:
select * from mytable where msisdn like '%7%'
or
select * from mytable where msisdn like '56655%'
Given this linq query against an EF data context:
var customers = data.Customers.Where(c => c.EmailDomain.StartsWith(term))
You’d expect it to produce SQL like this, right?
SELECT {cols} FROM Customers WHERE EmailDomain LIKE #term+’%’
Well, actually, it does something like this:
SELECT {cols} FROM Customer WHERE ((CAST(CHARINDEX(#term, EmailDomain) AS int)) = 1)
Do you know why?
Also, replacing the Where selector to:
c => c.EmailDomain.Substring(0, term.Length) == term
it runs 10 times faster but still produces some pretty yucky SQL.
NOTE: Linq to SQL correctly translates StartsWith into Like {term}%, and nHibernate has a dedicated LikeExpression.
I don't know about MS SQL server but on SQL server compact LIKE 'foo%' is thousands time faster than CHARINDEX, if you have INDEX on seach column. And now I'm sitting and pulling my hair out how to force it use LIKE.
http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/1b835b94-7259-4284-a2a6-3d5ebda76e4b
The reason is that CharIndex is a lot faster and cleaner for SQL to perform than LIKE. The reason is, that you can have some crazy "LIKE" clauses. Example:
SELECT * FROM Customer WHERE EmailDomain LIKE 'abc%de%sss%'
But, the "CHARINDEX" function (which is basically "IndexOf") ONLY handles finding the first instance of a set of characters... no wildcards are allowed.
So, there's your answer :)
EDIT: I just wanted to add that I encourage people to use CHARINDEX in their SQL queries for things that they didn't need "LIKE" for. It is important to note though that in SQL Server 2000... a "Text" field can use the LIKE method, but not CHARINDEX.
Performance seems to be about equal between LIKE and CHARINDEX, so that should not be the reason. See here or here for some discussion. Also the CAST is very weird because CHARINDEX returns an int.
charindex returns the location of the first term within the second term.
sql starts with 1 as the first location (0 = not found)
http://msdn.microsoft.com/en-us/library/ms186323.aspx
i don't know why it uses that syntax but that's how it works
I agree that it is no faster, I was retrieving tens of thousands of rows from our database with the letter i the name. I did find however that you need to use > rather than = ... so use
{cols} FROM Customer WHERE ((CAST(CHARINDEX(#term, EmailDomain) AS int)) > 0)
rather than
{cols} FROM Customer WHERE ((CAST(CHARINDEX(#term, EmailDomain) AS int)) = 1)
Here are my two tests ....
select * from members where surname like '%i%' --12 seconds
select * from sc4_persons where ((CAST(CHARINDEX('i', surname) AS int)) > 0) --12 seconds
select * from sc4_persons where ((CAST(CHARINDEX('i', surname) AS int)) = 1) --too few results