Parse SQL Column into separate columns - sql

I'm looking to parse a sql column result into separate columns. Here is an example of the column...
Detail - Column name
'TaxID changed from "111" to "333". Address1 changed from "542 Test St." to "333 Test St". State changed from "FL" to "DF". Zip changed from "11111" to "22222". Country changed from "US" to "MX". CurrencyCode changed from "usd" to "mxn". RFC Number changed from "" to "test". WarehouseID changed from "6" to "1". '
I need to take the old TAXID, new TAXID, old country, and new country and put them in separate columns.
The Detail column will always have TAXID and Country, however the challenging part is that they don't always have the rest of data that I listed above. Sometimes it will contain city and other times it won't. This means the order is always different.

I would create a tsql proc, use a case statement.
Do a count of the double quotes. If there are 8 oairs, you know that you old and new values, only 4 pairs you only have new values.
Then using the double quotes as indexes for your substring, you can put the vales into the table.
Good luck!

I was able to come up with something that worked.
In case anyone else gets a situation like this again perhaps posting my code will help.
DECLARE #document varchar(350);
set #document = 'TaxID changed from "111" to "222"'
declare #FIRSTQUOTE int
declare #SECONDQUOTE int
declare #OLDTAXID nvarchar(40)
declare #firstlength int
declare #ThirdQuote int
declare #FourthQuote int
declare #secondlength int
declare #NewTAXID nvarchar(40)
declare #oneplussecondquote int
declare #oneplusthirdquote int
select #FirstQuote = CHARINDEX('"',#document)
set #FIRSTQUOTE = #FIRSTQUOTE + 1
select #SECONDQUOTE = CHARINDEX('"',#document,#FIRSTQUOTE)
set #firstlength = #SECONDQUOTE - #FIRSTQUOTE
select #OLDTAXID = SUBSTRING(#document,#FIRSTQUOTE,#firstlength)
set #oneplussecondquote = #SECONDQUOTE + 1
select #ThirdQuote = CHARINDEX('"',#document,#oneplussecondquote)
set #oneplusthirdquote = #ThirdQuote + 1
select #FourthQuote = CHARINDEX('"',#document,#oneplusthirdquote)
select #secondlength = #FourthQuote - #oneplusthirdquote
select #NewTAXID = SUBSTRING(#document,#oneplusthirdquote,#secondlength)
You can switch out the string for this: 'Country changed from "US" to "MX"'
And it would grab the old country and new country

Related

One-Time Use Randomized Number

Tables(columns) that are important here (there are more in my actual DB but I simplified):
Patients(PatientID, PatientNumber, DOB, Weight, RandomCode)
RandomNumbers(RandomNumberID, Available)
Sites(SiteID, SiteNumber)
Patients does not contain any data and is to be populated via a 3rd party GUI. RandomNumbers contains 50 entries. When a patient's data is first added to Patients, a random number 1-50 is selected, which is tied to RandomNumberID. The "available" column in RandomNumbers is treated as a boolean (T meaning available, F meaning unavailable). After the RandomNumberID is tied to a patient, that RandomNumberID cannot be used again (Available is switched to "F"). If an already used RandomNumber is assigned to a patient upon data entry, another randomly selected RandomNumberID is selected until one is found where Available is T.
Here is the storedproc that I've written so far:
GO
CREATE PROCEDURE uspPatientEntry
#intPatientID AS INTEGER OUTPUT
,#intPatientNumber AS INTEGER
,#intSiteID AS INTEGER
,#intRandomCode AS INTEGER
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRANSACTION
SELECT #intPatientID = MAX (intPatientID) + 1
FROM TPatients TP (TABLOCKX)
SELECT #intPatientID = COALESCE(#intPatientID, 1)
SELECT #intPatientNumber = CONCAT(#intSiteID, #intPatientID)
INSERT INTO TPatients (intPatientID, intPatientNumber, intSiteID, intRandomCodeID)
VALUES (#intPatientID, #intPatientNumber, #intSiteID, #intRandomCode)
COMMIT TRANSACTION
GO
And here is another function I wrote to test it out:
DECLARE #intPatientID AS INTEGER = 0;
DECLARE #intSiteNumber AS INTEGER = 0;
DECLARE #intPatientNumber AS INTEGER = CONCAT(#intSiteNumber, #intPatientID);
DECLARE #intRandomCode AS INTEGER = FLOOR(RAND()*50)+1; -- This just picks a random integer 1-40. <- this is the heart of my question
EXECUTE uspPatientEntry #intPatientID OUTPUT, #intPatientNumber, 2, #intRandomCode
Would something like this work? Ignore syntax, just the general idea:
DECLARE #intRandomCode AS INTEGER;
SELECT #intRandomCode = FLOOR(RAND()*50+1;
FROM TRandomCodes TRC
WHERE TRC.blnAvailable = "T"
UPDATE TRandomCodes TRC
SET TRC.blnAvailable = "F"
WHERE #intRandomCode = TRC.intRandomNumberID;
Thank you

Combining current date code with stored procedure ti use in PowerBi

To get the required table I have to input the value "201801" into the stored procedure query. I want to place the following code:
SELECT CONVERT(nvarchar(6), GETDATE(), 112)
In the following Sp:
USE [MDAmanager]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[sqSupplierBalances]
#Period = 201801,
#SupplierString = 'select SupplierID from Suppliers ',
#SelectionString = 'select * from vSupplierBalances order by
ControlOfficeName, PortfolioName, OwnerEntityName, RegionName,
PropertyName, PropertyManagerName, Custom1Name, Custom2Name,
ServiceTypeDescription, AnalysisCode, SupplierName',
#WithCommitments = NULL,
#UserID = NULL,
#ExcludeInDispute = NULL,
#IncludeSupplierPropertyReference = NULL
SELECT 'Return Value' = #return_value
GO
Is it possible to assign a value to the first code example and replace the "201801" in the second code example with that variable. I have been trying this but not getting it right.
Update: So I realize M query functions and SQL server functions are different. I don't how to go about answering my own question but I figured I'd give the answer here anyway.
I replaced the initial date code with:
Perdiod0 = (Date.Year(DateTime.LocalNow()) * 100) +
Date.Month(DateTime.LocalNow())
And then just replaced the 201801 with:
'" & Text.From(Period0) & "'
Seems to work now

Converting ID values in substring of varchar to it's lookup values

I have a SQL column of type varchar that is meant to contain SQL conditions, eg (3 rows below):
WHERE Language = 1 OR Region = 10
WHERE Color= 3 OR Region = 10
WHERE Status = 1 OR Region = 10 AND Language = 1
I need to create a query to get the lookup values of these that can be sent to any non technical person. The output would be:
WHERE Language = English OR Region = Canada
WHERE Color= Red OR Region = Canada
WHERE Status = Active OR Region = Canada AND Language = English
I know I can first put all the lookups in a temp table and then use the REPLACE function, but I was wondering if there's any better (and shorter) way to do this? Any help would be appriciated.
Thanks.
I would create subquery column values ready to replace originals, f.eks for Regions:
SELECT
CONCAT('%Region = ', Region,'%') ConditionToJoin,
CONCAT('Region = ', Region) ConditionToFind,
CONCAT('Region = ', RegionName) ConditionToReplace
FROM Regions
The join this sub query with condition rows using LIKE operator and ConditionToJoin column.
There is also a question if you need to handle situations like:
Region=1
Region =1
etc...
Alternatively you could write user function to wash data and perform all replacements, something like:
CREATE FUNCTION replaceLookups(#condition VARCHAR(MAX))
RETURNS VARCHAR(MAX)
BEGIN
#string_replacement VARCHAR(MAX), #string_pattern VARCHAR(MAX);
SET #string_pattern = SELECT TOP 1 CONCAT('Region = ', Region) FROM Regions WHERE #condition LIKE CONCAT('%Region = ', Region, '%')
SET #string_replacement = SELECT TOP 1 CONCAT('Region = ', RegionName) FROM Regions WHERE #condition LIKE CONCAT('%Region = ', Region, '%')
SET #ret = REPLACE(#condition, #string_pattern, #string_replacement)
... --and so on for each lookup
RETURN #ret
END
Word of warning. Above code was written from top of my head - might need some work. Also I wouldn't expect great performance.

How to split a column by the number of white spaces in it with SQL?

I've got a single column that contains a set of names in it. I didn't design the database so that it contains multiple values in one column, but as it is I've got to extract that information now.
The problem is that in one field I've got multiple values like in this example:
"Jack Tom Larry Stan Kenny"
So the first three should be one group, and the other ones on the far right are another group. (Basically the only thing that separates them in the column is a specific number of whitespace between them, let's say 50 characters.)
How can I split them in pure SQL, so that I can get two columns like this:
column1 "Jack Tom Larry"
column2 "Stan Kenny"
A fairly simplistic answer would be to use a combination of left(), right() and locate(). Something like this (note I've substituted 50 spaces with "XXX" for readability):
declare global temporary table session.x(a varchar(100))
on commit preserve rows with norecovery;
insert into session.x values('Jack Tom LarryXXXStan Kenny');
select left(a,locate(a,'XXX')-1),right(a,length(a)+1-(locate(a,'XXX')+length('XXX'))) from session.x;
If you need a more general method of extracting the nth field from a string with a given separator, a bit like the split_part() function in PostgreSQL, in Ingres your options would be:
Write a user defined function using the Object Management Extension (OME). This isn't entirely straightforward but there is an excellent example in the wiki pages of Actian's community site to get you started:
http://community.actian.com/wiki/OME:_User_Defined_Functions
Create a row-producing procedure. A bit more clunky to use than an OME function, but much easier to implement. Here's my attempt at such a procedure, not terribly well tested but it should serve as an example. You may need to adjust the widths of the input and output strings:
create procedure split
(
inval = varchar(200) not null,
sep = varchar(50) not null,
n = integer not null
)
result row r(x varchar(200)) =
declare tno = integer not null;
srch = integer not null;
ptr = integer not null;
resval = varchar(50);
begin
tno = 1;
srch = 1;
ptr = 1;
while (:srch <= length(:inval))
do
while (substr(:inval, :srch, length(:sep)) != :sep
and :srch <= length(:inval))
do
srch = :srch + 1;
endwhile;
if (:tno = :n)
then
resval=substr(:inval, :ptr, :srch - :ptr);
return row(:resval);
return;
endif;
srch = :srch + length(:sep);
ptr = :srch;
tno = :tno + 1;
endwhile;
return row('');
end;
select s.x from session.x t, split(t.a,'XXX',2) s;

Substring from right by character SQL

I have a string(s)-
CO_CS_SV_Integrate_WP_BalancingCostRiskandComplexityinYourDRStrat_Apr-Jun
Or
CO_CS_SV_CommVaultTapSponsorship_WP_GartnerNewsletterSmartIdeaforBigData_Jan-Mar
Or
CO_CS_IA_eMedia_WP_Top5eDiscoveryChallengesSolved_Apr-Jun
I need to get the asset name associated with the campaign which is in the campaign name.
So for example "Balancing Cost Risk and Complexity in Your DR Strat"
would be the asset associated with the first campaign-
"CO_CS_SV_Integrate_WP_BalancingCostRiskandComplexityinYourDRStrat_Apr-Jun"
That is my goal. I want to get just that from the string ("Balancing Cost Risk and Complexity in Your DR Strat".
But I don't see how to strip out the asset from the campaign name. It is not consistent on position or anything else???
I think I can go from the right and and find the second "_"
But I don't know the syntax. I get as far as -
select campaign.name
,Right (campaign.name, charindex('_', REVERSE(campaign.name))) as Test
from campaign
which gives me -
_Apr-Jun
Any help or direction would be greatly appreciated
Thanks.
You could create a scalar function that accept the string, like the following:
CREATE FUNCTION myFunction
(
#str varchar(300)
)
RETURNS varchar(300)
AS
BEGIN
declare #reverse varchar(200),#idx1 int,#idx2 int
set #reverse = reverse(#str)
set #idx1 = CHARINDEX('_',#reverse)
set #idx2 = CHARINDEX('_',#reverse,#idx1+1)
return reverse(substring(#reverse,#idx1+1,#idx2-#idx1-1))
END
You can try with the following example:
select dbo.myFunction('CO_CS_SV_Integrate_WP_BalancingCostRiskandComplexityinYourDRStrat_Apr-Jun');