I am trying to convert my DB2 stored procedure to SQL Server and I'm not sure about this xmltable function
DECLARE #IN_AR_UTL_DATA_XML XML
DECLARE #WS_ACCOUNT_NO DECIMAL(13,0)
DECLARE #WS_BILL_NO INT
SET #IN_AR_UTL_DATA_XML = '<CUST_CHARGES>
<AC_NO>50001233</AC_NO>
<INVOICE_NO>63877</INVOICE_NO>
<INVOICELINES>
<INVOICELINE>
<INVOICE_ENTITY>V52259108</INVOICE_ENTITY>
<ENTITY_TYPE>W</ENTITY_TYPE>
<REVENUE_CLASS>7811</REVENUE_CLASS>
<SEQUENCE_NO>1</SEQUENCE_NO>
<IS_FIXED>false</IS_FIXED>
<IS_BACKOUT>true</IS_BACKOUT>
<DATE_ORIG_INVOICE>20190801</DATE_ORIG_INVOICE>
<CODE_INVOICE_ITM_TYPE>B</CODE_INVOICE_ITM_TYPE>
<INVOICE_ITEM_TIMESTMP>2018-09-
18T09:36:33.703214</INVOICE_ITEM_TIMESTMP>
<TOTAL_AMOUNT>300.44</TOTAL_AMOUNT>
<CHARGES>
<WATER_CHARGES>0</WATER_CHARGES>
<SEWER_CHARGES>300.44</SEWER_CHARGES>
<WATER_CHARGE>-222.3</WATER_CHARGE>
<SEWER_CHARGE>0</SEWER_CHARGE>
<WATER_REFUND>222.3</WATER_REFUND>
<SEWER_DISCOUNT>300.44</SEWER_DISCOUNT>
<CAP_DISCOUNT>0</CAP_DISCOUNT>
<SUR_CHARGE>0</SUR_CHARGE>
</CHARGES>
</INVOICELINE>
<INVOICELINE>
<INVOICEING_ENTITY>V52259109</INVOICEING_ENTITY>
<ENTITY_TYPE>W</ENTITY_TYPE>
<REVENUE_CLASS>611</REVENUE_CLASS>
<SEQUENCE_NO>2</SEQUENCE_NO>
<IS_FIXED>false</IS_FIXED>
<IS_BACKOUT>false</IS_BACKOUT>
<DATE_ORIG_INVOICE>20180918</DATE_ORIG_INVOICE>
<CODE_INVOICE_ITM_TYPE>C</CODE_INVOICE_ITM_TYPE>
<INVOICE_ITEM_TIMESTMP>2018-09-
18T09:36:34.238839</INVOICE_ITEM_TIMESTMP>
<TOTAL_AMOUNT>-938.21</TOTAL_AMOUNT>
<CHARGES>
<WATER_CHARGES>0</WATER_CHARGES>
<SEWER_CHARGES>-938.21</SEWER_CHARGES>
<WATER_CHARGE>694.2</WATER_CHARGE>
<SEWER_CHARGE>0</SEWER_CHARGE>
<WATER_REFUND>-694.2</WATER_REFUND>
<SEWER_DISCOUNT>-938.21</SEWER_DISCOUNT>
<CAP_DISCOUNT>0</CAP_DISCOUNT>
<SUR_CHARGE>0</SUR_CHARGE>
</CHARGES>
</INVOICELINE>
</INVOICELINES>
</CUST_CHARGES>'
Above is my sample XML code. Below is my DB2 statement that needs to be converted.
SELECT
WS_AC_NO = TABLE1.XmlCol1.value('AC_NO[1]' ,'DECIMAL(13,0)')
,WS_INVOICE_NO = TABLE1.XmlCol1.value('INVOICE_NO[1]','SMALLINT')
--,INVOICE_ENTITY = TABLE1.XmlCol1.value('#INVOICE_ENTITY','VARCHAR(9)') -- This is not working.
,INVOICE_ENTITY = TABLE2.XmlCol2.value('INVOICELINES[1]/INVOICELINE[1]/INVOICE_ENTITY[1]','VARCHAR(9)')
,ENTITY_TYPE = TABLE1.XmlCol1.value('INVOICELINES[1]/INVOICELINE[1]/ENTITY_TYPE[1]' ,'CHAR(1)')
,REVENUE_CLASS = TABLE1.XmlCol1.value('INVOICELINES[1]/INVOICELINE[1]/REVENUE_CLASS[1]' ,'SMALLINT')
,SEQUENCE_NO = TABLE1.XmlCol1.value('INVOICELINES[1]/INVOICELINE[1]/SEQUENCE_NO[1]' ,'SMALLINT')
,TOTAL_AMOUNT = TABLE1.XmlCol1.value('INVOICELINES[1]/INVOICELINE[1]/TOTAL_AMOUNT[1]' ,'DECIMAL(11,2)')
,CHARGE = TABLE1.XmlCol1.value('INVOICELINES[1]/INVOICELINE[1]/XmlCol[1]','DECIMAL(11,2)') -- I need all sub charge values
,'W' AS CHARGE_TYPE
,1 AS ORDER_SEQUENCE_NO
,DATE_ORIG_BILL = TABLE1.XmlCol1.value('INVOICELINES[1]/INVOICELINE[1]/DATE_ORIG_BILL[1]' ,'INT')
,CODE_BILL_ITM_TYPE = TABLE1.XmlCol1.value('INVOICELINES[1]/INVOICELINE[1]/CODE_BILL_ITM_TYPE[1]','VARCHAR(1)')
,BILL_ITEM_TIMESTMP = TABLE1.XmlCol1.value('INVOICELINES[1]/INVOICELINE[1]/BILL_ITEM_TIMESTMP[1]','DATETIME2(6)')
FROM #IN_AR_UTL_DATA_XML.nodes('/CUAT_CHARGES') TABLE1(XmlCol1)
CROSS APPLY #IN_AR_UTL_DATA_XML.nodes('/CUAT_CHARGES/INVOICELINES/INVOICELINE')
TABLE2(XmlCol2)
Can you please share SQL Server equivalent syntax for this? SQL Server version 2014 / 2016 is preferred. Thanks.
Perhaps something like:
DECLARE #IN_AR_UTL_DATA_XML XML
DECLARE #WS_ACCOUNT_NO DECIMAL(13,0)
DECLARE #WS_BILL_NO INT
SET #IN_AR_UTL_DATA_XML = '<CUST_CHARGES>
<AC_NO>50001233</AC_NO>
<INVOICE_NO>63877</INVOICE_NO>
<INVOICELINES>
<INVOICELINE>
<INVOICE_ENTITY>V52259108</INVOICE_ENTITY>
<ENTITY_TYPE>W</ENTITY_TYPE>
<REVENUE_CLASS>7811</REVENUE_CLASS>
<SEQUENCE_NO>1</SEQUENCE_NO>
<IS_FIXED>false</IS_FIXED>
<IS_BACKOUT>true</IS_BACKOUT>
<DATE_ORIG_INVOICE>20190801</DATE_ORIG_INVOICE>
<CODE_INVOICE_ITM_TYPE>B</CODE_INVOICE_ITM_TYPE>
<INVOICE_ITEM_TIMESTMP>2018-09-
18T09:36:33.703214</INVOICE_ITEM_TIMESTMP>
<TOTAL_AMOUNT>300.44</TOTAL_AMOUNT>
<CHARGES>
<WATER_CHARGES>0</WATER_CHARGES>
<SEWER_CHARGES>300.44</SEWER_CHARGES>
<WATER_CHARGE>-222.3</WATER_CHARGE>
<SEWER_CHARGE>0</SEWER_CHARGE>
<WATER_REFUND>222.3</WATER_REFUND>
<SEWER_DISCOUNT>300.44</SEWER_DISCOUNT>
<CAP_DISCOUNT>0</CAP_DISCOUNT>
<SUR_CHARGE>0</SUR_CHARGE>
</CHARGES>
</INVOICELINE>
<INVOICELINE>
<INVOICEING_ENTITY>V52259109</INVOICEING_ENTITY>
<ENTITY_TYPE>W</ENTITY_TYPE>
<REVENUE_CLASS>611</REVENUE_CLASS>
<SEQUENCE_NO>2</SEQUENCE_NO>
<IS_FIXED>false</IS_FIXED>
<IS_BACKOUT>false</IS_BACKOUT>
<DATE_ORIG_INVOICE>20180918</DATE_ORIG_INVOICE>
<CODE_INVOICE_ITM_TYPE>C</CODE_INVOICE_ITM_TYPE>
<INVOICE_ITEM_TIMESTMP>2018-09-
18T09:36:34.238839</INVOICE_ITEM_TIMESTMP>
<TOTAL_AMOUNT>-938.21</TOTAL_AMOUNT>
<CHARGES>
<WATER_CHARGES>0</WATER_CHARGES>
<SEWER_CHARGES>-938.21</SEWER_CHARGES>
<WATER_CHARGE>694.2</WATER_CHARGE>
<SEWER_CHARGE>0</SEWER_CHARGE>
<WATER_REFUND>-694.2</WATER_REFUND>
<SEWER_DISCOUNT>-938.21</SEWER_DISCOUNT>
<CAP_DISCOUNT>0</CAP_DISCOUNT>
<SUR_CHARGE>0</SUR_CHARGE>
</CHARGES>
</INVOICELINE>
</INVOICELINES>
</CUST_CHARGES>'
SELECT
WS_AC_NO = r.chargeNode.value('AC_NO[1]' ,'DECIMAL(13,0)')
,WS_INVOICE_NO = r.chargeNode.value('INVOICE_NO[1]','INT')
,INVOICE_ENTITY = i.lineNode.value('INVOICE_ENTITY[1]','VARCHAR(9)')
,ENTITY_TYPE = i.lineNode.value('ENTITY_TYPE[1]' ,'CHAR(1)')
,REVENUE_CLASS = i.lineNode.value('REVENUE_CLASS[1]' ,'INT')
,SEQUENCE_NO = i.lineNode.value('SEQUENCE_NO[1]' ,'INT')
,TOTAL_AMOUNT = i.lineNode.value('TOTAL_AMOUNT[1]' ,'DECIMAL(11,2)')
,WATER_CHARGES = i.lineNode.value('(CHARGES/WATER_CHARGE)[1]','DECIMAL(11,2)') -- I need all sub charge values
,'W' AS CHARGE_TYPE
,1 AS ORDER_SEQUENCE_NO
FROM #IN_AR_UTL_DATA_XML.nodes('/CUST_CHARGES') r(chargeNode)
CROSS APPLY chargeNode.nodes('INVOICELINES/INVOICELINE') i(lineNode)
Related
I need to execute a procedure from python as below
DECLARE
#LayoutID INT = 9
,#PrivateFL INT =0
,#FromDate DATETIME = '20100101'
,#ToDate DATETIME = '20211001'
,#VesselIDs dbo.UniqueIntList
insert into #VesselIDs values (202),(330)
EXEC usp_GetComments #LayoutID, #PrivateFL, #FromDate, #ToDate, #VesselIDs
How do i pass '#VesselIDs' as parameter while executing it using python?
I tried below but its not working
list = [202,330]
storedProc = "EXEC usp_GetComments #LayoutID=?, #PrivateFL=?, #FromDate=?, #ToDate=?,
#VesselIDs=?"
params = (9,0,'20100101','20211001',list)
Do as below:
storedProc = "EXEC usp_GetComments #LayoutID=?, #PrivateFL=?, #FromDate=?, #ToDate=?, #VesselIDs=?"
fktvp = [(202,),(330,)]
fkparams = (9,0,'20100101','20211001',fktvp)
cursor.execute( storedProc, fkparams )
Station = SN[0]
Asset = AN[0]
y = ASD[0]
z = ACD[0]
cursor = conn.cursor()
cursor.execute('SELECT * FROM station')
cursor.execute('''
UPDATE station
SET ActualStartDate = y, ActualCompletionDate = z
WHERE StationName = #Station and AssetNumber = #Asset
''')
conn.commit()
I am getting this error:
('42000', '[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Must declare the scalar variable "#Station". (137) (SQLExecDirectW)')
I would like to get the values from 4 numpy arrays above, SN[0], AN[0], SCD[0] SSD[0] and use these values in the UPDATE Query.
Is it possible to execute this?
As noted in the pyodbc documentation, your parameter placeholders must be question marks and you must pass the parameter values along with the SQL command text in the .execute() call:
sql = """\
UPDATE station
SET ActualStartDate = ?, ActualCompletionDate = ?
WHERE StationName = ? and AssetNumber = ?
"""
params = (y, z, Station, Asset)
cursor.execute(sql, params)
Ok first, I'm storing Lat/Long location in a column of type geography in my SQL Server table.
I try to get stores in a specific bounding box using STContains method, the only way I found to use the geography point, was by concatening the Lat/Long with STR convertion:
DECLARE #boundingBox geography;
SET #boundingBox = geography::Parse('POLYGON((...))');
...
SELECT Store.Id, Store.Name, Store.Location.Lat, Store.Location.Long,
#boundingBox.STContains(
geography::Parse('POINT(' + STR(Store.Location.Lat, 20, 12) + ' '
+ STR(Store.Location.Long, 20, 12) + ')'))
It works, but it's ugly and asking if there's a cleaner way to write this.
I setup 2 test Polygons geo and geo2. One using Parse method and the other using STPolyFromText method.
declare #geo geography
= geography::STPolyFromText('POLYGON ((73.250684 34.198599, 73.250598 34.199324, 73.250343 34.200021, 73.249927 34.200663, 73.249369 34.201226, 73.248688 34.201688, 73.247912 34.202031, 73.247069 34.202243, 73.246193 34.202314, 73.245317 34.202243, 73.244474 34.202031, 73.243698 34.201688, 73.243017 34.201226, 73.242458 34.200663, 73.242043 34.200021, 73.241788 34.199324, 73.241701 34.198599, 73.241788 34.197874, 73.242043 34.197177, 73.242458 34.196535, 73.243017 34.195972, 73.243698 34.19551, 73.244474 34.195167, 73.245317 34.194956, 73.246193 34.194884, 73.247069 34.194956, 73.247912 34.195167, 73.248688 34.19551, 73.249369 34.195972, 73.249927 34.196535, 73.250343 34.197177, 73.250598 34.197874, 73.250684 34.198599, 73.250684 34.198599))', 4326)
declare #geo2 geography
= geography::Parse('POLYGON ((73.250684 34.198599, 73.250598 34.199324, 73.250343 34.200021, 73.249927 34.200663, 73.249369 34.201226, 73.248688 34.201688, 73.247912 34.202031, 73.247069 34.202243, 73.246193 34.202314, 73.245317 34.202243, 73.244474 34.202031, 73.243698 34.201688, 73.243017 34.201226, 73.242458 34.200663, 73.242043 34.200021, 73.241788 34.199324, 73.241701 34.198599, 73.241788 34.197874, 73.242043 34.197177, 73.242458 34.196535, 73.243017 34.195972, 73.243698 34.19551, 73.244474 34.195167, 73.245317 34.194956, 73.246193 34.194884, 73.247069 34.194956, 73.247912 34.195167, 73.248688 34.19551, 73.249369 34.195972, 73.249927 34.196535, 73.250343 34.197177, 73.250598 34.197874, 73.250684 34.198599, 73.250684 34.198599))')
declare #outsidePoint geography
= geography::STPointFromText('POINT(-122.34900 47.65100)', 4326),
#insidePoint geography
= geography::STPointFromText('POINT(73.2438096 34.1989505)', 4326)
select
geo = #geo,
geoString = #geo.ToString(),
IsValid = #geo.STIsValid(),
doesContainOutsidePoint = #geo.STContains(#outsidePoint),
doesIntersectOutsidePoint = #geo.STIntersects(#outsidePoint),
doesContainInsidePoint = #geo.STContains(#insidePoint),
doesIntersectInsidePoint = #geo.STIntersects(#insidePoint)
select
geo = #geo2,
geoString = #geo2.ToString(),
IsValid = #geo2.STIsValid(),
doesContainOutsidePoint = #geo2.STContains(#outsidePoint),
doesIntersectOutsidePoint = #geo2.STIntersects(#outsidePoint),
doesContainInsidePoint = #geo2.STContains(#insidePoint),
doesIntersectInsidePoint = #geo2.STIntersects(#insidePoint)
Both of them seem to work for me - with the following results:
I can query from my Polygon table in the DB using both the STContains and STIntersects methods of the geography type.
So if .STContains is returning 0 for you that means the Point is not inside the box. Maybe you could post a sample Polygon and Point where it is returning 0 but should return 1 that might help.
I have an existing SQL Server 2008 database which has a number of views, stored procedures and functions.
I want to be able to SELECT data from one of these SQL functions and limit the number of rows that it returns in a paging scenario.
I have tried using .Select with .Skip and .Take as follows:
public IEnumerable<Product> CallSqlFunction_dbo_Search_Products_View(int clientId,
string environmentCode,
int sessionId)
{
IEnumerable<Product> results;
using (var db = _dbConnectionFactory.Open())
{
results = db.Select<Product>(#"
SELECT
*
FROM
[dbo].[Search_Products_View]
(
#pClientID,
#pEnvironmentCode,
#pSessionId
)", new
{
pClientID = clientId,
pEnvironmentCode = environmentCode,
pSessionId = sessionId
})
.Skip(0)
.Take(1000);
db.Close();
}
return results;
}
This produces the following SQL which is executed on the SQL Server.
exec sp_executesql N'
SELECT
*
FROM
[dbo].[Search_Products_View]
(
#pClientID,
#pEnvironmentCode,
#pSessionId
)',N'#pClientID int,#pEnvironmentCode varchar(8000),#pSessionId int',#pClientID=0,#pEnvironmentCode='LIVE',#pSessionId=12345
It means that this query returns 134,000 products, not the first page of 1000 I was expecting. The paging happens on the API server once the SQL Server has returned 134,000 rows.
Is it possible to use ORMLite so that I can get it to generate the paging in the query similar to this:
exec sp_executesql N'
SELECT
[t1].*
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY [t0].[ProductId], [t0].[ProductName])
FROM
[dbo].[Search_Products_View](#pClientId, #pEnvironmentCode, #pSessionId) AS [t0]
WHERE
(LOWER([t0].[ProductStatus]) = #pProductStatus1) OR (LOWER([t0].[ProductStatus]) = #pProductStatus2) OR (LOWER([t0].[ProductStatus]) = #pProductStatus3)
) AS [t1]
WHERE
[t1].[ROW_NUMBER] BETWEEN #pPageNumber + 1 AND #pPageNumber + #pNumberOfRowsPerPage
ORDER BY [t1].[ROW_NUMBER]',
N'#pClientId decimal(9,0),#pEnvironmentCode char(3),#pSessionId decimal(9,0),#pProductStatus1 varchar(8000),#pProductStatus2 varchar(8000),#pProductStatus3 varchar(8000),#pPageNumber int,#pNumberOfRowsPerPage int',
#pClientId=0,#pEnvironmentCode='LIVE',#pSessionId=12345,#pProductStatus1='1',#pProductStatus2='2',#pProductStatus3='3',#pPageNumber=0,#pNumberOfRowsPerPage=1000
OrmLite will use the windowing function hack in <= SQL Server 2008 for its typed queries but not for Custom SQL. You'll need to include the entire SQL (inc. Windowing function) into your Custom SQL.
If you do this a lot I'd suggest wrapping the Windowing Function SQL Template in an extension method so you can easily make use of it in your custom queries, e.g:
results = db.Select<Product>(#"
SELECT
*
FROM
[dbo].[Search_Products_View]
(
#pClientID,
#pEnvironmentCode,
#pSessionId
)"
.InWindowingPage(0,1000), new
{
pClientID = clientId,
pEnvironmentCode = environmentCode,
pSessionId = sessionId
})
If you want to use DB Params for the offsets you'll need some coupling to use conventional param names:
results = db.Select<Product>(#"
SELECT
*
FROM
[dbo].[Search_Products_View]
(
#pClientID,
#pEnvironmentCode,
#pSessionId
)"
.InWindowingPage(), new
{
pClientID = clientId,
pEnvironmentCode = environmentCode,
pSessionId = sessionId,
pPageNumber = 0,
pNumberOfRowsPerPage = 100
})
In my Teradata Stored Procedure, I want to have a for loop cursor against a dynamic sql.
Below is the code snippet
SET get_exclude_condition = '';
SET colum_id = 'SELECT MIN (parent_criteria_id) ,MAX (parent_criteria_id) FROM arc_mdm_tbls.intnl_mtch_criteria WHERE act_ind = 1 AND criteria_typ = ''Exclude'' AND mtch_technique_id ='||mtch_technique_id||';' ;
PREPARE input_stmt FROM colum_id;
OPEN flex_cursor;
FETCH flex_cursor INTO parent_criteria_id_min , parent_criteria_id_max ;
CLOSE flex_cursor;
SET get_exclude_condition = '';
WHILE (parent_criteria_id_min <= parent_criteria_id_max)
DO
SET get_exclude_condition = get_exclude_condition || '( ';
SET for_loop_stmt = 'SELECT criteria FROM arc_mdm_tbls.intnl_mtch_criteria WHERE act_ind = 1 AND mtch_technique_id ='||mtch_technique_id||' AND criteria_typ= ''Exclude'' AND parent_criteria_id ='||parent_criteria_id_min||';';
FOR for_loop_rule AS c_cursor_rule CURSOR FOR
for_loop_stmt
DO
Can I declare a for loop cursor like this ?
Or do I need to have something like this only ?
FOR for_loop_rule AS c_cursor_rule CURSOR FOR
SELECT rule_id
FROM arc_stage_tbls.assmt_scoring_rules
WHERE rule_typ = :v_RuleType
ORDER BY rule_id
DO
I mean can I first frame the dynamic sql and then have a for loop cursor on top of that or with the cursor declaration only I need to have a static sql query ?
Please clarify.
While you haven't posted everything that the stored procedure is trying to accomplish, it does appear that what you are asking can be accomplished using SET based logic and not looping through a cursor. If you need to parameterize the 'mtch_technique_id' you can use a Teradata macro which will allow you to maintain a SET based approach.
Here is the SQL for creating a macro that returns a result set based on my interpretation of what your snippet of the stored procedure is trying to accomplish:
REPLACE MACRO {MyDB}.Intnl_Mtch_Criteria(mtch_technique_id INTEGER) AS
(
SELECT criteria
FROM arc_mdm_tbls.intnl_mtch_criteria
WHERE act_ind = 1
AND (much_technique_id, criteria_typ) IN
(SELECT MIN((parent_criteria_id), MAX (parent_criteria_id)
FROM arc_mdm_tbls.intnl_mtch_criteria
WHERE act_ind = 1
AND criteria_typ = 'Exclude'
AND mtch_technique_id = :mtch_technique_id;
);