T-SQL SUBSTRING with CHARINDEX AS LENGTH part is returning too much text - tsql

I have ploughed through the massive amount of queries on here relating to SUBSTRING and CHARINDEX but I cannot find one that answers my query.
I am extracting a single part of a long piece of text but it is returning 48 characters too much. E.g. in the first row of the results the length should be 44 characters rather than the 92 characters it is giving. I split out the various parts of the query into the last 3 columns to get the starting position and the length but when I put it together it doesn't work correctly. What am I doing wrong?
My code: (Updated to make consumable I hope)
IF OBJECT_ID('tempdb.dbo.#WQuery', 'U') IS NOT NULL
DROP TABLE #WQuery
CREATE TABLE #WQuery
(
IncidentID VARCHAR(100),
Description VARCHAR(250),
)
INSERT INTO #WQuery
(IncidentID, Description)
VALUES
('B209BBA0-9039-ED11-81AD-0050569FE3BD','<b>Please indicate your company''s export status:</b><br />New to export (less than 1 years experience)<br /><br /><b>What is the destination market for your goods/services?</b><br />United Kingdom<br /><br />'),
('13A75070-0F38-ED11-81AD-0050569FE3BD','<b>Please indicate your company''s export status:</b><br />Novice exporter (1-3 years experience)<br /><br /><b>What is the destination market for your goods/services?</b><br />Kazakhstan <br /><br />'),
('D2926CA8-EB28-ED11-81AC-0050569FE3BD','<b>Please indicate your company''s export status:</b><br />New to export (less than 1 years experience)<br /><br /><b>What is the destination market for your goods/services?</b><br />Zambia (central Africa)<br/'),
('7226B826-DF24-ED11-81AC-0050569FE3BD','<b>Please indicate your company''s export status:</b><br />Experienced exporter (3+ years experience in multiple markets)<br /><br /><b>What is the destination market for your goods/services?</b><br />Spain<br'),
('E636692C-3C22-ED11-81AC-0050569FE3BD','<b>Please indicate your company''s export status:</b><br />New to export (less than 1 years experience)<br /><br /><b>What is the destination market for your goods/services?</b><br />India<br /><br />'),
('C13937A0-EF16-ED11-81AC-0050569FE3BD','<b>Please indicate your company''s export status:</b><br />New to export (less than 1 years experience)<br /><br /><b>What is the destination market for your goods/services?</b><br />Rotterdam<br /><br /><b>')
;
select
i.incidentid
, i.description
, SUBSTRING(i.description,
CHARINDEX('export status:</b><br />', i.description)+LEN('export status:</b><br />'),
CHARINDEX('<br /><br /><b>What is the destination market',i.description) - (CHARINDEX('export status:</b><br />', i.description)-LEN('export status:</b><br />')) ) As ExportStatus
--substring(string,start,length)--
--length is the number of characters to extract - must be positive--
--split the substring above to test the values--
,CHARINDEX('export status:</b><br />', i.description)+LEN('export status:</b><br />') as start
,CHARINDEX('<br /><br /><b>What is the destination market',i.description) as secondQStart
,CHARINDEX('<br /><br /><b>What is the destination market',i.description) - CHARINDEX('export status:</b><br />', i.description)-LEN('export status:</b><br />') as length
--charindex(substring,string,start)--
from #WQuery i
DROP TABLE #WQuery;
The expected results for column 3 (export status) should be:
However I am getting this:
When I added the code from the column 'Length' into the parameter of the SUBSTRING query it gave an error.
Msg 537, Level 16, State 3, Line 3
Invalid length parameter passed to the LEFT or SUBSTRING function.
When I added the brackets around that part of the SUBSTRING the query ran but as you can see it is not returning the same number of characters and the 'length' in the last column.
I am struggling to understand why the length parameter in the SUBSTRING query is not working the same as the same code in the 'length' column. And I also do not understand why the code needs brackets in the parameter of SUBSTRING query to work or throws the error.

Your text is almost valid XHTML. You just need to fix up the ends of the lines in some cases, I assume this is a copy-paste error.
For example, <br />Spain<br should be <br />Spain<br />, and Rotterdam<br /><br /><b> should be Rotterdam<br /><br /><b />.
Now you can just use XQuery to get the right piece of text, which appears to be the first text not enclosed by any node.
SELECT ExportStatus = CAST(wq.Description AS xml).value('(/text())[1]', 'nvarchar(max)')
FROM #WQuery wq
db<>fiddle

Related

How to format currency in Filemaker ExecuteSQL istruction?

there is a way to format currencies in the result of an ExecuteSQL?
Sql keyword "FORMAT" doesn't work.
the calculation is:
ExecuteSQL ( "
SELECT expenses.user, ' - € ', SUM(expenses.value)
FROM expenses
GROUP BY expenses.user"
;" " ; ¶ ) ;
my output is
Ray - € 10000.1
John - € 44926.97
Tim - € 315.88
I need to get
Ray - € 10.000,10
John - € 44.926,97
Tim - € 315,88
It is (sort of) possible to format a Number field, but not a sum - because an aggregate function cannot be used as an argument to other functions.
However, you could process the query result and format the amounts using Filemaker's native functions. Or (probably simpler) use a summary field instead of ExecuteSQL().

Postgres XML parsing - Calculate the sum of multiple nodes of the same name using XPath

I have an xml snippet as below:
<OpCodeLaborInfo JobStatus="F" UpSellFlag="N" JobNo="1" OpCode="02TTZ10K" OpCodeDesc="10K SERVICE">
<TechInfo ActualHrsWorked="2.50" CustTechRate="27.00" TechHrs="0.00" TechName="JEFF SELLERS" TechNo="4816" />
<TechInfo ActualHrsWorked="0.00" CustTechRate="27.00" TechHrs="0.70" TechName="JEFF SELLERS" TechNo="4816" />
<BillTimeRateHrs BillRate="129.97" />
<CCCStmts Correction="PERFORMED 10K SERVICE" Complaint="LUBE OIL FILTER CHANGE, TIRE ROTATION, PERFORM MULTI POINT" />
<CCCStmts Correction="X" Complaint="INSPECTION, INSPECT FILTERS AND RECOMMEND, INSPECT BRAKES," />
<CCCStmts Complaint="BELTS AND HOSES" />
<RoAmts DlrCost="18.90" PayType="Cust" AmtType="Job" TotalAmt="59.12" />
</OpCodeLaborInfo>
<OpCodeLaborInfo JobStatus="F" UpSellFlag="N" JobNo="2" OpCode="02TTZ10K" OpCodeDesc="10K SERVICE">
<TechInfo ActualHrsWorked="2.50" CustTechRate="27.00" TechHrs="1.00" TechName="JEFF SELLERS" TechNo="4816" />
<TechInfo ActualHrsWorked="0.00" CustTechRate="27.00" TechHrs="0.00" TechName="JEFF SELLERS" TechNo="4816" />
<BillTimeRateHrs BillRate="129.97" />
<CCCStmts Correction="PERFORMED 10K SERVICE" Complaint="LUBE OIL FILTER CHANGE, TIRE ROTATION, PERFORM MULTI POINT" />
<CCCStmts Correction="X" Complaint="INSPECTION, INSPECT FILTERS AND RECOMMEND, INSPECT BRAKES," />
<CCCStmts Complaint="BELTS AND HOSES" />
<RoAmts DlrCost="18.90" PayType="Cust" AmtType="Job" TotalAmt="59.12" />
</OpCodeLaborInfo>
I need to calculate the sum of the TechInfo/#TechHrs for each OpCodeLaborInfo. I tried the following:
unnest(xpath('sum(//dns:RepairOrder/dns:RoRecord/dns:Rolabor/dns:OpCodeLaborInfo/dns:TechInfo/#TechHrs[1])'::text,
data_detail.ro_data_xml,
ARRAY[ARRAY['dns'::text, 'http://www.starstandards.org/STAR'::text]]))::text::numeric AS lbrsoldhours
but this seems to return the sum of the Tech Hours inside both the OpCodeLaborInfo nodes. Could someone be able to tell me how I can tweak the xpath so as to get the desired result.
So basically I need :
Job
Tech Hrs
1
sum(0.00+0.70)
2
sum(1.00+0.00)
I would solve this using xmltable()
select d.job, sum(t.hours)
from data_detail d
cross join xmltable (
'/OpCodeLaborInfo/TechInfo'
passing d.ro_data_xml
columns hours numeric path '#TechHrs') as t
group by d.job;
Online example
The XPath is probably not correct as the XPath you have shown doesn't match your sample XML data. Your sample XML also doesn't contain a namespace, so I am not sure why you are passing one to xpath()
But if you need one, you can use something like this:
cross join xmltable (
xmlnamespaces ('http://www.starstandards.org/STAR' as dns),
'/dns:OpCodeLaborInfo/dns:TechInfo'
passing d.ro_data_xml
columns hours numeric path '#TechHrs') as t
xpath can also work fine:
SELECT job
, SUM((xpath('//#TechHrs', element))[1]::text::decimal)
FROM data_detail
, LATERAL (SELECT unnest(xpath('/OpCodeLaborInfo/TechInfo', ro_data_xml))) u(element)
GROUP BY job;
fiddle
(based on the fiddle of #a_horse_with_no_name)

TSQL query to extract a value between to char where a specific set of characters is there

I have a problem I can't seem to figure out. I am trying to extract capacity from a product description. It is always between two values, "," and "oz." however there could be other commas included in the description that are not part of what I'm trying to extract. Example value is , 15 oz., or , 2 oz.,
I'm trying to find values that have the oz in them and are between two commas and I have been completely unsuccessfully. I've tried many things, but here is the latest that I have tried today and I'm just getting an error.
SELECT SUBSTRING(
FullDescription,
CHARINDEX(',', FullDescription),
CHARINDEX('oz.',FullDescription)
- CHARINDEX(',', FullDescription)
+ Len('oz.')
)
from CatalogManagement.Product
Since the backwards pattern ,.zo is more recognisable, I'd go with the REVERSE function
Sample values:
"something, something more, 18oz., complete"
"shorter, 12oz., remainder"
"there is no capacity, in this, value"
"a bit more, 14oz, and some followups, maybe"
SELECT REVERSE(
SUBSTRING (
REVERSE(FullDescription),
CHARINDEX(',.zo', REVERSE(FullDescription)) + 1,
CHARINDEX(',', REVERSE(FullDescription), CHARINDEX(',.zo', REVERSE(FullDescription)) + 1) - CHARINDEX(',.zo', REVERSE(FullDescription)) - 1
)
)
FROM CatalogManagement.Product
WHERE FullDescription LIKE '%oz.,%'
You might use XML-splitting together with a XQuery predicate:
DECLARE #tbl TABLE(ID INT IDENTITY, YourString VARCHAR(MAX));
INSERT INTO #tbl VALUES('Here is one with an amount, 1 oz., some more text')
,('Here is one with no amount, some more text')
,('a, 10 oz.')
,('b, 20oz., no blank between oz and the number')
,('30oz., starts with the pattern, no leading comma');
SELECT t.*
,A.oz.value('.','nvarchar(max)') oz
FROM #tbl t
CROSS APPLY(SELECT CAST('<x>' + REPLACE((SELECT t.YourString AS [*] FOR XML PATH('')),',','</x><x>') + '</x>' AS XML)
.query('/x[contains(text()[1],"oz.")]')) A(oz);
The idea in short:
We use some string methods to replace commas with XML tags and to cast your string to XML. each fragment is placed within a decent <x> element.
We use a predicate to return just the fragments containing "oz.".
You can filter easily with
WHERE LEN(A.oz.value('.','nvarchar(max)'))>0

To find particular value in sql expression either by expression or by regular expression way

I have the following data in the value field.
Sample data
-------------------
cid value
--------------------
1 'This is test message for *NAME_FIRST* <br />*NAME_LAST*<br />We should strict to rules for inspections.<br /><br />Thanks,
2 'Hello *NAME_FIRST* <br />*NAME_LAST*<br />Hope you are doing good.<br /><br />Thanks,'
I want to find all such data that have NAME_FIRST OR NAME_LAST pattern in value. I wrote following select query but something is wrong and I am not able to get results.
SELECT * FROM template_custom_texts tct WHERE tct.cid = 1 AND tct.value = E'\\*(NAME_FIRST|NAME_LAST)\\*';
I used another way as well like this :
SELECT * FROM template_custom_texts tct WHERE tct.cid = 1 AND regexp_matches(tct.value, '(NAME_FIRST|NAME_LAST)', 'g');
In both query results do not arrive.
Try the below query:
SELECT *
FROM template_custom_texts
WHERE cid = 1 AND value ~ 'NAME_FIRST|NAME_LAST';
Bear in mind this query is case sensitive and you can replace ~ with ~* for case insensitive matching.
Have a read of the documentation for PostgreSQL pattern matching too: https://www.postgresql.org/docs/9.3/functions-matching.html.

Send query to CFWheels selectTag form helper, or list with commas in string elements

I have a query that returns names in <lastnamd>, <firstname> format such as
<cfquery name="instructorSelectList" dataSource="GIRSReport">
SELECT instructor_DBID,
last_name + ', ' + first_name as instructor_name,
hid
FROM instructors
WHERE working_status = 'active'
ORDER BY last_name, first_name
</cfquery>
I want to use this query for a selectTag form helper. If I do:
#selectTag
(
name="inst",
id="program",
options="#ValueList(instructorSelectList.instructor_name)#",
valueField="#ValueLIst(instructorSelectList.instructor_DBID)#",
display="#ValueList(instructorSelectList.instructor_name)#",
selected="",
label="HID",
multiple="no",
includeBlank="true",
size=1,
class="form-control",
prepend="<br/>"
)#
Then I get a list like <lastname1>, <firstname1>, <lastname2>, <firstname2>, ...
which is obviously not what I want.
If I just try to pass the options parameter a query, such as options="#instructorSelectList.instructor_name#", the options don't fill properly.
The idea is to use a form helper equivalent to
<cfselect
name="inst"
query="instructorSelectList"
queryPosition="below"
value="instructor_DBID"
display="instructor_name"
label="HID" size=1
class="form-control">
<option value=""></option>
</cfselect>
I think what you're needing is to pass a query name to Options, without quotes (or in quotes surrounded by hashes) while the column names are quoted.
#selectTag
(
name="inst",
id="program",
options=instructorSelectList,
valueField="instructor_DBID",
textField="instructor_name",
selected="",
label="HID",
multiple="no",
includeBlank="true",
size=1,
class="form-control",
prepend="<br/>"
)#
More Info: CFWheels selectTag() documentation