I have a follow up question with regards to a similar issue I'm having, as the one posted on this thread: Why when converting SQL Real to Numeric does the scale slightly increase?.
I'm using Sybase IQ 16. I have a column called - StrikePrice with float datatype in a table called ProductTb. For a certain record, the value in the table for this column is StrikePrice=22411.39.
When I try to convert it in either decimal or numeric as follows : convert(decimal(31,5), StrikePrice) OR convert(numeric(31,5), StrikePrice), this gives a result as - 22411.39189.
How do I make sure that this shows the value as - 22411.39000 instead of 22411.39189? Is there any workaround that I can use to achieve this?
Thanks in advance for your help.
Example of what I'm looking for:
When I have a value of let's say : 0.0090827, the desired output needed is : 0.00908 i.e. limited to 5 digits after the decimal. And when I have a value of : 22411.39, the desired output is : 22411.39000.
Adding more details
This(above explained issue) seems to work fine on Sybase ASE and the results are what I expect on ASE. The issue is only on Sybase IQ. See details below:
Sybase ASE (15.7):
select TradeNum, StrikePrice as "Original Strike Price in Database", convert(numeric(31, 5), StrikePrice) as "Converted Strike Price"
from ProductTb where TradeNum in (8463676,72372333)
TradeNum Original Strike Price in Database Converted Strike Price
8463676 61.65 61.65000
72372333 85.6 85.60000
72372333 85.6 85.60000
Sybase IQ (16):
select TradeNum, StrikePrice as "Original Strike Price in Database", convert(numeric(31, 5), StrikePrice) as "Converted Strike Price"
from ProductTb where TradeNum in (8463676,72372333)
TradeNum Original Strike Price in Database Converted Strike Price
72372333 85.6 85.59999
72372333 85.6 85.59999
8463676 61.65 61.64999
Looks like you have a couple SQL function options:
round()
SELECT ROUND( 123.234, 1 ) FROM iq_dummy
=> 123.200
truncnum()
SELECT TRUNCNUM( 655, -2 ) FROM iq_dummy
=> 600
SELECT TRUNCNUM( 655.348, 2 ) FROM iq_dummy
=> 655.340
I don't have access to an IQ instance at the moment but I'm thinking something like the following may work:
convert(decimal(31,5), round(StrikePrice,2))
convert(numeric(31,5), truncnum(StrikePrice,2))
UPDATE
The updated question appears to state there are 2 different rounding requirements based on the value in the StrikePrice column:
if < 1.0 then keep 5 decimal places of accuracy
if > 1.0 then keep 2 decimal places of accuracy
NOTE: I'm guessing at the threshold here (< 1.0 vs > 1.-) as this has not been explicitly stated in the question; if OP decides the threshold is something other than 1.0 this should be easy enough to address ... just change the 1.0 in the query (below) to the new threshold value
This logic can be implemented via a case statement.
I don't have access to an IQ instance but the following ASE example should be easy enough to convert to IQ:
create table testtab (a float)
go
insert testtab values (61.649999) -- > 1.0 so round to 2 decimal places
insert testtab values (0.2234234) -- < 1.0 so round to 5 decimal places
go
select convert(numeric(31,5),
case when a < 1.0
then round(a,5)
else round(a,2)
end
)
from testtab
go
--------------
61.65000 -- rounded to 2 decimal places
0.22342 -- rounded to 5 decimal places
I'm trying to consume some logging data that I'm receiving in XML.
I've got the XML packet in SQL Server, after significant work cleaning up the data to make it valid XML. (And grab other attributes from JSON wrappers, etc)
But now I'm stuck trying to read the XML to retrieve the values from individual lines
My sample XML looks like:
<?xml version="1.0" encoding="UTF-8"?>
<general>
<group id="0" comment="Application">
<N1 comment="Start Date">2020-11-03T00:05:48Z</N1>
<N2 comment="Name/Description">ProgramName</N2>
<N3 comment="Version Number">ReleaseNumber</N3>
<N5 comment="Compilation Date">2020-10-01T01:05:01Z</N5>
<N6 comment="Up Time">1899-12-30T00:00:56Z</N6>
</group>
<group id="1" comment="Exception">
<N1 comment="Date">Tue, 3 Nov 2020 11:06:45 +1100</N1>
<N2 comment="Address">MemoryAddress</N2>
<N3 comment="Module Name">ModuleName</N3>
<N4 comment="Module Version">ModuleVersionNumber</N4>
<N5 comment="Type">ExceptionType</N5>
<N6 comment="Message">Insufficient memory for this operation.</N6>
<N7 comment="ID">ExceptionID</N7>
<N8 comment="Count">1</N8>
<N9 comment="Status">New</N9>
<N11 comment="Sent">0</N11>
</group>
</general>
The problem is, I'm not sure how to query Group 0 N6, I've been using:
DECLARE #x XML
select #X
,LEFT(#X.value('(/log/#version)[1]','VARCHAR(10)') ,10)
But I can't wrap my head around the necessary XQuery/XPath to pull the value of the child row inside a specifically numbered group.
#X.value('(/log/group[1]/N2)[1]','VARCHAR(50)') ,10)
Can anyone share the magic that would make it possible to query the value from N2? I suspect the answer is in Contains, but I'm having problems finding the write code tutorial to make the instructions snap into place in my head.
(This is complicated because I want to draw 10 values from 3 different groups in the XML. To query a different version of the Logs I'm receiving (which I broke into being a flat file so I could pull the attributes) I ended up running:
,ExceptionAddress=LEFT(#X.value('(/Doc/Log/General/Line_2.2/#Value)[1]','VARCHAR(10)') ,10)
,ExceptionType=LEFT(#X.value('(/Doc/Log/General/Line_2.5/#Value)[1]','VARCHAR(50)') ,50)
,ExceptionMessage=LEFT(#X.value('(/Doc/Log/General/Line_2.6/#Value)[1]','NVARCHAR(200)') ,200)
,FormClass=LEFT(#X.value('(/Doc/Log/General/Line_4.1/#Value)[1]','VARCHAR(50)') ,50)
,FormText=LEFT(#X.value('(/Doc/Log/General/Line_4.2/#Value)[1]','NVARCHAR(50)') ,50)
,ControlClass=LEFT(#X.value('(/Doc/Log/General/Line_4.3/#Value)[1]','VARCHAR(50)') ,50)
,ControlText=LEFT(#X.value('(/Doc/Log/General/Line_4.4/#Value)[1]','NVARCHAR(50)') ,50)
,OSType=LEFT(#X.value('(/Doc/Log/General/Line_6.1/#Value)[1]','VARCHAR(50)') ,50)
,OSBuild=LEFT(#X.value('(/Doc/Log/General/Line_6.2/#Value)[1]','VARCHAR(50)') ,50)
,OSUpdate=LEFT(#X.value('(/Doc/Log/General/Line_6.3/#Value)[1]','VARCHAR(50)') ,50)
Your XML is flawed in many ways, that is the reason why there is no easy-cheesy answer:
DECLARE #xml XML=
'<general>
<group id="0" comment="Application">
<N1 comment="Start Date">2020-11-03T00:05:48Z</N1>
<N2 comment="Name/Description">ProgramName</N2>
<N3 comment="Version Number">ReleaseNumber</N3>
<N5 comment="Compilation Date">2020-10-01T01:05:01Z</N5>
<N6 comment="Up Time">1899-12-30T00:00:56Z</N6>
</group>
<group id="1" comment="Exception">
<N1 comment="Date">Tue, 3 Nov 2020 11:06:45 +1100</N1>
<N2 comment="Address">MemoryAddress</N2>
<N3 comment="Module Name">ModuleName</N3>
<N4 comment="Module Version">ModuleVersionNumber</N4>
<N5 comment="Type">ExceptionType</N5>
<N6 comment="Message">Insufficient memory for this operation.</N6>
<N7 comment="ID">ExceptionID</N7>
<N8 comment="Count">1</N8>
<N9 comment="Status">New</N9>
<N11 comment="Sent">0</N11>
</group>
</general>';
--this gets a list you might write into a temp table and proceed from there
SELECT A.gr.value('#id','int') groupId
,A.gr.value('#comment','nvarchar(max)') groupComment
,B.nd.value('#comment','nvarchar(max)') NComment
,B.nd.value('text()[1]','nvarchar(max)') NContent
FROM #xml.nodes('/general/group') A(gr)
OUTER APPLY A.gr.nodes('*') B(nd);
--this tries to get your EAV-data in a tabular format
SELECT A.gr.value('#id','int') groupId
,A.gr.value('#comment','nvarchar(max)') groupComment
,A.gr.value('(*[#comment="Compilation Date"])[1]','datetime') NCompilationDate
,A.gr.value('(*[#comment="Date"])[1]','nvarchar(max)') NDate
,A.gr.value('(*[#comment="Count"])[1]','int') NCount
FROM #xml.nodes('/general/group') A(gr);
Why is your XML flawed:
You should not name number elements (N1, N2, N3...). All of them should have the same name. If there really is a need for the number add an attribute (nmbr="1").
You are mixing date-time formats. Within XML you should use the ISO8601 only (as it is in your first group). The worst case is culture and language dependant content. In my (German) system the "Tue" for Tuesday would break this.
My suggestion was:
Use my second approach, but create one query for each type of group and read them separately into temp tables with a given set of typed columns, then proceed with this.
Ok, so I've managed to find a possible solution for this.
Incase the way I phrased this question helps anyone else, mysolutions were:
,LEFT(#X.value('(/log/general/group[1]/N6)[1]','VARCHAR(50)') ,50) --Find first GROUP, returend first result for N6
,LEFT(#X.value('(/log/general/group[#id="0"]/N6)[1]','VARCHAR(50)') ,50) --Find group with ID=0, return first result for N6
,LEFT(#X.value('(/log/general/group[#id="1"]/N6)[1]','VARCHAR(50)') ,50) --Find group with ID=1, reture first result for N6
,LEFT(#X.value('(/log/general/group[2]/N2)[1]','VARCHAR(50)') ,50) --Find second GROUP, returend first result for N6
Note, informed heavily by Red Gate Simple Talk whose article finally made it click for me. https://www.red-gate.com/simple-talk/sql/learn-sql-server/the-xml-methods-in-sql-server/
Super keen to see other better solutions if anyone has them though.
In ArcGis geological point represent in mssql database as hexa values
eg : 0x**7214**0000010C00000000004C0D4100000000004C0D41
I used mssql geospatial function as below
$query1="DECLARE #Point GEOMETRY
SET #Point = geometry::STGeomFromText('POINT (240000 240000)',0) INSERT INTO main (id, mname, pdata) VALUES (1,'update_1',#Point)";
but it retuns hexa values as 0x**0000**0000010C00000000004C0D4100000000004C0D41
first 4 characters are different from the required outcome , is there any otherway to get that ? I dont have much idea about geospatial function. String replace is not possible thanks.
I am expecting 0x72140000010C00000000004C0D4100000000004C0D41
I assume you're using SRID 5234, which is for Sri Lanka? In your STGeomFromText you have 0 as the second parameter, which is the SRID. Set that to 5234 and you will get the correct output.
I've got a table in a SQL Server 2008 database with an nvarchar(MAX) column containing XML data. The data represents search criteria. Here's what the XML looks like for search criteria with one top-level "OR" group containing one single criterion and a nested two-criterion "AND" group.
<?xml version="1.0" encoding="utf-16"?>
<SearchCriterionGroupArgs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SingleCriteria>
<SearchCriterionSingleArgs>
<Operator>Equals</Operator>
<Value>test</Value>
<FieldIDs>
<int>1026</int>
<int>478</int>
</FieldIDs>
<EntityID>92</EntityID>
</SearchCriterionSingleArgs>
</SingleCriteria>
<GroupCriteria>
<SearchCriterionGroupArgs>
<SingleCriteria>
<SearchCriterionSingleArgs>
<Operator>GreaterThan</Operator>
<Value>2010-01-23</Value>
<FieldIDs>
<int>1017</int>
</FieldIDs>
<EntityID>92</EntityID>
</SearchCriterionSingleArgs>
<SearchCriterionSingleArgs>
<Operator>LessThan</Operator>
<Value>2013-01-23</Value>
<FieldIDs>
<int>1018</int>
</FieldIDs>
<EntityID>92</EntityID>
</SearchCriterionSingleArgs>
</SingleCriteria>
<GroupCriteria />
<EntityID>92</EntityID>
<LogicalOperator>AND</LogicalOperator>
</SearchCriterionGroupArgs>
</GroupCriteria>
<EntityID>92</EntityID>
<LogicalOperator>OR</LogicalOperator>
</SearchCriterionGroupArgs>
Given a an input set of FieldID values, I need to search the table to find if there are any records whose search criteria refer to one of those values (these are represented in the "int" nodes under the "FieldIDs" nodes.)
By running this query:
select CAST(OptionalConditions as xml).query('//FieldIDs')
from tblMyTable
I get the results:
<FieldIDs>
<int>1026</int>
<int>478</int>
</FieldIDs>
<FieldIDs>
<int>1017</int>
</FieldIDs>
<FieldIDs>
<int>1018</int>
</FieldIDs>
(currently there's only one record in the table with xml data in it.)
But I'm just getting started with this stuff and I don't know what the notation would be to check those lists for the existence of any of an arbitrary set of FieldIDs. I don't need to retrieve any particular nodes, just true or false for whether the input field IDs are referenced anywhere in the search.
Thanks for your help!
Edit: using Ranon's solution, I got it working using a query like this:
SELECT *
FROM myTable
WHERE CAST(OptionalConditions as xml).exist('//FieldIDs/int[.=(1019,111,1018)]') = 1
Fetch all FieldIDs and compare them with the set id IDs to check against. XQuery's =-operator compares in a set-based semantics, so if one of the IDs on the left side equal on one the right, this expression will evaluate to true.
//FieldIDs/int = (42, 478)
As "478" is a FieldID, this query will return true. "42" is one not available.
I'm not sure about whether you will be able to cast the result to some sql-server-boolean-type as I haven't got one running, but you will easily be able to try out yourself.
If you're also interested in the nodes contained, you could use this query:
//FieldIDs/int[. = (42,478)]
I am trying to use XQuery in SQL Server 2005 to update xml saved in a column. Here is a sample of the data I need to update.
<Length>3</Length>
<Width>5</Width>
<Depth>6</Depth>
<Area xsi:nil="true" />
<Volume xsi:nil="true" />
I need to set the area and volume to values from a different table. I am creating a CTE for the update. There is other logic that I have omitted, but I have verified that the CTE contains the correct data for the update:
;with Volume (DocumentID, Volume) As
(
Select DocumentID, Volume from tbl
)
and I am using the following XQuery SQL statement to try to update the table.
UPDATE tbl_Archive
SET XML.modify(' declare namespace x="http://www.redacted.com";
replace value of (/x:Document/x:Volume/text())[1]
with sql:column("Volume.Volume")')
From Volume where volume.documentID = tbl_Archive.DocumentID
I get 1 row affected, but when I look at the XML it hasn't changed, and I can't figure out what needs to be fixed to make it work. The node is untyped, if that makes any difference.
Update wont work if there's no text to replace.. the XPath /x:Document/x:Volume/text())[1] will return an empty set.
Try insert...
UPDATE tbl_Archive
SET XML.modify(' declare namespace x="http://www.redacted.com";
insert text {sql:column("Volume.Volume")}
as first into (/x:Document/x:Volume)[1]')
From Volume where volume.documentID = tbl_Archive.DocumentID
..you'll then need to remove the nil="true" attribute..
Something like this maybe..
update tbl_Archive set XML.modify('delete /*:Document/*:Volume[text()]/#xsi:nil')