Need help in regexp_substr and regexp_like - oracle10g

I have data like below in once column(having 5 records)
Failed to process Batch task. An exception occured while building Bond(00010068, BOND, CLOSE, ICT, TOK, EOD, Bond_EOD): You are trying to get DBond that doesn't exist. (DeliveryCount=2)
Failed to process Batch task. An exception occured while building Bond(00010068, BOND, CLOSE, ICT, TOK, EOD, Bond_EOD): You are trying to get DBond that doesn't exist. (DeliveryCount=0)
Failed to process Batch task. There was an error generating the XML document. (DeliveryCount=0)
Failed to process Batch task. There was an error generating the XML document. (DeliveryCount=0)
Failed to process Batch task. There was an error generating the XML document. (DeliveryCount=0)
Here i need to get the data like ( need data which is eclosed in () )
00010068, BOND, CLOSE, ICT, TOK, EOD, Bond_EOD
00010068, BOND, CLOSE, ICT, TOK, EOD, Bond_EOD
and i don't want to other that above mentioned data.
apart from that have to split the row data into columns like
col1 col2 col3 col4 col5 col6 col7
-------------------------------------------------------------------------
00010068 BOND CLOSE ICT TOK EOD Bond_EOD
Can you please some on help me on this

with tab as
(select 'Failed to process Batch task. An exception occured while building Bond(00010068, BOND, CLOSE, ICT, TOK, EOD, Bond_EOD): You are trying to get DBond that doesn''t exist. (DeliveryCount=2)' s from dual
union all select 'Failed to process Batch task. An exception occured while building Bond(00010068, BOND, CLOSE, ICT, TOK, EOD, Bond_EOD): You are trying to get DBond that doesn''t exist. (DeliveryCount=0)' from dual
union all select 'Failed to process Batch task. There was an error generating the XML document. (DeliveryCount=0)' from dual
union all select 'Failed to process Batch task. There was an error generating the XML document. (DeliveryCount=0)' from dual
union all select 'Failed to process Batch task. There was an error generating the XML document. (DeliveryCount=0)' from dual
)
select trim(regexp_substr(parsed, '[^,]+', 1, 1)) col1
, trim(regexp_substr(parsed, '[^,]+', 1, 2)) col2
, trim(regexp_substr(parsed, '[^,]+', 1, 3)) col3
, trim(regexp_substr(parsed, '[^,]+', 1, 4)) col4
, trim(regexp_substr(parsed, '[^,]+', 1, 5)) col5
, trim(regexp_substr(parsed, '[^,]+', 1, 6)) col6
, trim(regexp_substr(parsed, '[^,]+', 1, 7)) col7
from
(
select substr(regexp_substr(s, 'bond\([^)]+', 1, 1, 'i'), 6) parsed
from tab where regexp_like(s, 'bond\(.+?\)', 'i')
);
regexp_like(s, 'bond\(.+?\)', 'i') returns true if a string s contains "bond(...)", case insensitive ("i" flag); .+? is a nongreedy at least one symbol - anything until the first ")"
substr(regexp_substr(s, 'bond\([^)]+', 1, 1, 'i'), 6) - get only the desired substring (... from "bond(...)"). Oracle10g doesn't support subexpressions so we have to make do with common substr to cut "bond("
Finally, get Nth "none-comma" sequence from the parsed string

Related

LPAD function errors when used in WITH variable in Redshift

Can you tell me why this is throwing an error in Redshift?
WITH Testing_PADDING AS (SELECT '12345678' AS column1)
SELECT LPAD(column1, 9,'0') FROM Testing_PADDING;
Here is the error I receive:
"Invalid operation: failed to find conversion function from "unknown" to text;"
Redshift can't determine data type from the context, so you need to explicitly set it
WITH Testing_PADDING AS (SELECT '12345678'::text AS column1)
SELECT
LPAD(column1, 9, '0')
FROM Testing_PADDING;
I suspect that one of your strings isn't being seen as text - likely the column1 text. (Sorry don't have a cluster up not to test)
Try:
WITH Testing_PADDING AS (SELECT '12345678'::text AS column1)
SELECT LPAD(column1, 9,'0'::text) FROM Testing_PADDING;

How to group by in FOR XML clause in SQL Server 2014?

I have this schema in fiddle
My code:
SELECT
MUID, weekcounter,
STUFF((SELECT ',' + Category
FROM tb EE
WHERE EE.MUID = E.MUID AND Ranknum <= 3
FOR XML PATH, TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') AS listStr
FROM tb E
GROUP BY E.MUID, E.weekcounter
I am getting wrong output like this:
I am expecting this output :
I don't have option to use string_aggr() in SQL Server 2014.
I believe if you want to get the desired output, you'd have to use the two columns you want to group by in the correlated subquery (in the STUFF part), too.
Try this code:
SELECT
MUID, weekcounter,
STUFF((SELECT ',' + Category
FROM tb EE
WHERE EE.MUID = E.MUID
AND EE.weekcounter = E.weekcounter
AND Ranknum <= 3
FOR XML PATH, TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') AS listStr
FROM
tb E
GROUP BY
E.MUID, E.weekcounter

SQL: PIVOTting Count & Percentage against a column

I'm trying to produce a report that shows, for each Part No, the results of tests on those parts in terms of the numbers passed and failed, and the percentages passed and failed.
So far, I have the following:
SELECT r2.PartNo, [Pass] AS Passed, [Fail] as Failed
FROM
(SELECT ResultID, PartNo, Result FROM Results) r1
PIVOT (Count(ResultID) FOR Result IN ([Pass], [Fail])) AS r2
ORDER By r2.PartNo
This is half of the solution (the totals for passes and fails); the question is, how do I push on and include percentages?
I haven't tried yet, but I imagine that I can start again from scratch, and build up a series of subqueries, but this is more a learning exercise - I want to know the 'best' (most elegant or most efficient) solution, so I thought I'd seek advice.
Can I extend this PIVOT query, or should I take a different approach?
DDL:
CREATE TABLE RESULTS (
[ResultID] [int] NOT NULL,
[SerialNo] [int] NOT NULL,
[PartNo] [varchar](10) NOT NULL,
[Result] [varchar](10) NOT NULL);
DML:
INSERT INTO Results VALUES (1, '100', 'ABC', 'Pass')
INSERT INTO Results VALUES (2, '101', 'DEF', 'Pass')
INSERT INTO Results VALUES (3, '100', 'ABC', 'Fail')
INSERT INTO Results VALUES (4, '102', 'DEF', 'Pass')
INSERT INTO Results VALUES (5, '102', 'DEF', 'Pass')
INSERT INTO Results VALUES (6, '102', 'DEF', 'Fail')
INSERT INTO Results VALUES (7, '101', 'DEF', 'Fail')
UPDATE:
My solution, based on bluefeet's answer is:
SELECT r2.PartNo,
[Pass] AS Passed,
[Fail] as Failed,
ROUND(([Fail] / CAST(([Pass] + [Fail]) AS REAL)) * 100, 2) AS PercentFailed
FROM
(SELECT ResultID, PartNo, Result FROM Results) r1
PIVOT (Count(ResultID) FOR Result IN ([Pass], [Fail])) AS r2
ORDER By r2.PartNo
I've ROUNDed a FLOAT(rather than CAST to DECIMAL twice) because its a tiny bit more efficient, and I've also decided that we only real need the failure %age.
It sounds like you just need to add a column for Percent Passed and Percent Failed. You can calculate those columns on your PIVOT.
SELECT r2.PartNo
, [Pass] AS Passed
, [Fail] as Failed
, ([Pass] / Cast(([Pass] + [Fail]) as decimal(5, 2))) * 100 as PercentPassed
, ([Fail] / Cast(([Pass] + [Fail]) as decimal(5, 2))) * 100 as PercentFailed
FROM
(
SELECT ResultID, PartNo, Result
FROM Results
) r1
PIVOT
(
Count(ResultID)
FOR Result IN ([Pass], [Fail])
) AS r2
ORDER By r2.PartNo

Dynamic pivot - how to obtain column titles parametrically?

I wish to write a Query for SAP B1 (t-sql) that will list all Income and Expenses Items by total and month by month.
I have successfully written a Query using PIVOT, but I do not want the column headings to be hardcoded like: Jan-11, Feb-11, Mar-11 ... Dec-11.
Rather I want the column headings to be parametrically generated, so that if I input:
--------------------------------------
Query - Selection Criteria
--------------------------------------
Posting Date greater or equal 01.09.10
Posting Date smaller or equal 31.08.11
[OK] [Cancel]
the Query will generate the following columns:
Sep-10, Oct-10, Nov-10, ..... Aug-11
I guess DYNAMIC PIVOT can do the trick.
So, I modified one SQL obtained from another forum to suit my purpose, but it does not work. The error message I get is Incorrect Syntax near 20100901.
Could anybody help me locate my error?
Note: In SAP B1, '[%1]' is an input variable
Here's my query:
/*Section 1*/
DECLARE #listCol VARCHAR(2000)
DECLARE #query VARCHAR(4000)
-------------------------------------
/*Section 2*/
SELECT #listCol =
STUFF(
( SELECT DISTINCT '],[' + CONVERT(VARCHAR, MONTH(T0.RefDate), 102)
FROM JDT1
FOR XML PATH(''))
, 1, 2, '') + ']'
------------------------------------
/*Section 3*/
SET #query = '
SELECT * FROM
(
SELECT
T0.Account,
T1.GroupMask,
T1.AcctName,
MONTH(T0.RefDate) as [Month],
(T0.Debit - T0.Credit) as [Amount]
FROM dbo.JDT1 T0
JOIN dbo.OACT T1 ON T0.Account = T1.AcctCode
WHERE
T1.GroupMask IN (4,5,6,7) AND
T0.[Refdate] >= '[%1]' AND
T0.[Refdate] <= '[%2]'
) S
PIVOT
(
Sum(Amount)
FOR [Month] IN ('+#listCol+')
) AS pvt
'
--------------------------------------------
/*Section 4*/
EXECUTE (#query)
I don't know SAP, but a couple of things spring to mind:
It looks like you want #listCol to contain a collection of numbers within square brackets, for example [07],[08],[09].... However, your code appears not to put a [ at the start of this string.
Try replacing the lines
T0.[Refdate] >= '[%1]' AND
T0.[Refdate] <= '[%2]'
with
T0.[Refdate] >= ''[%1]'' AND
T0.[Refdate] <= ''[%2]''
(I also added a space before the AND in the first of these two lines while I was editing your question.)

Update column to be different aggregate values

I am creating a script that for "merging" and deleting duplicate rows from a table. The table contains address information, and uses an integer field for storing information about the email as bit flags (column name lngValue). For example, lngValue & 1 == 1 means its the primary address.
There are instances of the same email being entered twice, but sometimes with different lngValues. To resolve this, I need to take the lngValue from all duplicates and assign them to one surviving record and delete the rest.
My biggest headache so far as been with the "merging" of the records. What I want to do is bitwise or all lngValues of duplicate records together. Here is what I have so far, which only finds the value of all lngValues bitwise or'ed together.
Warning: messy code ahead
declare #duplicates table
(
lngInternetPK int,
lngContactFK int,
lngValue int
)
insert into #duplicates (lngInternetPK, lngContactFK, lngValue)
(
select tblminternet.lngInternetPK, tblminternet.lngContactFK, tblminternet.lngValue from tblminternet inner join
(select strAddress, lngcontactfk, count(*) as count from tblminternet where lngValue & 256 <> 256 group by strAddress, lngcontactfk) secondemail
On tblminternet.strAddress = secondemail.strAddress and
tblminternet.lngcontactfk = secondemail.lngcontactfk
where count > 1 and tblminternet.strAddress is not null and tblminternet.lngValue & 256 <> 256 --order by lngContactFK, strAddress
)
update #duplicates set lngValue = t.val
from
(select (sum(dupes.lngValue) & 65535) as val from
(select here.lngInternetPK, here.lngContactFK, here.lngValue from tblminternet here inner join
(select strAddress, lngcontactfk, count(*) as count from tblminternet where lngValue & 256 <> 256 group by strAddress, lngcontactfk) secondemail
On here.strAddress = secondemail.strAddress and
here.lngcontactfk = secondemail.lngcontactfk
where count > 1 and here.strAddress is not null and here.lngValue & 256 <> 256) dupes, tblminternet this
where this.lngContactFK = dupes.lngContactFK
) t
where lngInternetPK in (select lngInternetPK from #duplicates)
Edit:
As requested here is some sample data:
Table Name: tblminternet
Column Names:
lngInternetPK
lngContactFK
lngValue
strAddress
Example row 1:
lngInternetPK: 1
lngContactFK: 1
lngValue: 33
strAddress: "me#myaddress.com"
Example row 2:
lngInternetPK: 2
lngContactFK: 1
lngValue: 40
strAddress: "me#myaddress.com"
If these two were merged here is the desired result:
lngInternetPK: 1
lngContactFK: 1
lngValue: 41
strAddress: "me#myaddress.com"
Other necessary rules:
Each contact can have multiple emails, but each email row must be distinct ( each email can only appear as one row).
SQL Server lacks native bitwise aggregates, that's why we need to emulate them.
The main idea here is to generate a set of bits from 0 to 15, for each bit apply the bitmask to the value and select MAX (which will give us an OR for a given bit), then select the SUM (which will merge the bit masks).
The we just update the first lngInternetPK for any given (lngContactFK, strValue) with the new value of lngValue, and delete all duplicates.
;WITH bits AS
(
SELECT 0 AS b
UNION ALL
SELECT b + 1
FROM bits
WHERE b < 15
),
v AS
(
SELECT i.*,
(
SELECT SUM(value)
FROM (
SELECT MAX(lngValue & POWER(2, b)) AS value
FROM tblmInternet ii
CROSS JOIN
bits
WHERE ii.lngContactFK = i.lngContactFK
AND ii.strAddress = i.strAddress
GROUP BY
b
) q
) AS lngNewValue
FROM (
SELECT ii.*, ROW_NUMBER() OVER (PARTITION BY lngContactFK, strAddress ORDER BY lngInternetPK) AS rn
FROM tblmInternet ii
) i
WHERE rn = 1
)
UPDATE v
SET lngValue = lngNewValue;
;WITH v AS
(
SELECT ii.*, ROW_NUMBER() OVER (PARTITION BY lngContactFK, strAddress ORDER BY lngInternetPK) AS rn
FROM tblmInternet ii
)
DELETE v
WHERE rn > 1
See this article in my blog for more detailed explanations:
SQL Server: aggregate bitwise OR
I believe the following query gets you what you want. This routine assumes a max of two duplicate addresses per contact. If there's more than one dup per contact, the query will have to be modified. I hope this helps.
Declare #tblminternet
Table
( lngInternetPK int,
lngContactFK int,
lngValue int,
strAddress varchar(255)
)
Insert Into #tblminternet
select 1, 1, 33, 'me#myaddress.com'
union
select 2, 1, 40, 'me#myaddress.com'
union
select 3, 2, 33, 'me#myaddress2.com'
union
select 4, 2, 40, 'me#myaddress2.com'
union
select 5, 3, 2, 'me#myaddress3.com'
--Select * from #tblminternet
Select Distinct
A.lngContactFK ,
A.lngValue | B.lngValue as 'Bitwise OR',
A.strAddress
From #tblminternet A, #tblminternet B
Where A.lngContactFK = B.lngContactFK
And A.strAddress = B.strAddress
And A.lngInternetPK != B.lngInternetPK
You can create SQL Server Aggregate functions in .NET that you can then implement in SQL server inline. I think this requires a minimum of SQL server 2005 and Visual Studio 2010. I did one using Visual Studio 2013 Community Edition (free even for commercial use) for use with .NET 2 and SQL Server 2005.
See the MSDN article: https://msdn.microsoft.com/en-us/library/91e6taax(v=vs.90).aspx
First you'll need to enable the CLR feature in SQL server: https://msdn.microsoft.com/en-us/library/ms131048.aspx
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
GO
RECONFIGURE;
GO
Create a SQL Server -> SQL Server Database Project
Right-click on the new project and select Properties
Configure the targeted SQL Server version under Project Settings
Configure the targeted CLR language under SQL CLR (such as VB)
Right-click on the new project and select Add -> New Item...
When the dialog pops up, select SQL Server -> SQL CLR VB -> SQL CLR VB Aggregate
Now you can write your bitwise code in VB:
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
<Serializable()> _
<Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.Native)> _
Public Structure AggregateBitwiseOR
Private CurrentAggregate As SqlTypes.SqlInt32
Public Sub Init()
CurrentAggregate = 0
End Sub
Public Sub Accumulate(ByVal value As SqlTypes.SqlInt32)
'Perform Bitwise OR against aggregate memory
CurrentAggregate = CurrentAggregate OR value
End Sub
Public Sub Merge(ByVal value as AggregateBitwiseOR)
Accumulate(value.Terminate())
End Sub
Public Function Terminate() As SqlInt32
Return CurrentAggregate
End Function
End Structure
Now deploy it: https://msdn.microsoft.com/en-us/library/dahcx0ww(v=vs.90).aspx
Build the project using the menu bar: Build -> Build ProjectName (if the build fails with error 04018 then download a new version of the data tools # http://msdn.microsoft.com/en-US/data/hh297027 or by going to the menu bar: Tools -> Extensions And Updates, then under updates select update for Microsoft SQL Server Update For Database Tooling)
Copy your compiled DLL to C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn and to C:\
Register the DLL:
CREATE ASSEMBLY [CLRTools] FROM ‘c:CLRTools.dll’ WITH PERMISSION_SET = SAFE
Create the aggregate in SQL:
CREATE AGGREGATE [dbo].[AggregateBitwiseOR](#value INT)
RETURNS INT
EXTERNAL NAME [CLRTools].[CLRTools.AggregateBitwiseOR];
If you get the error "Incorrect syntax near 'EXTERNAL'" then change the database compatibility level using following commands:
For SQL Server 2005: EXEC sp_dbcmptlevel 'DatabaseName', 90
For SQL Server 2008: EXEC sp_dbcmptlevel 'DatabaseName', 100
Test your code:
SELECT dbo.AggregateBitwiseOR(Foo) AS Foo FROM Bar
I found this article helpful: http://www.codeproject.com/Articles/37377/SQL-Server-CLR-Functions