I created a variable className and I assigned values to it.
I have another procedure in oracle that sends emails to me.
How do I pass this value into header and body of my email?
VARIABLE className varchar2(30)
:classname := 0;
BEGIN
FOR i IN
(
SELECT CLASS_INSTANCE_COUNT , CLASS_NAME
FROM MODEL_CLASS_COUNTS
WHERE TRUNC(COUNT_DATETIME) = TRUNC(SYSDATE)
)
LOOP
IF i.CLASS_INSTANCE_COUNT = 0
THEN
:className := i.CLASS_NAME;
EMAIL('myemail#col.com', 'email header: &className is 0', 'body: count for &className is 0');
END IF;
END LOOP;
END;
/
My guess is that you don't want to have either a SQL*Plus variable or a substitution variable. I'm guessing that you just want
BEGIN
FOR i IN
(
SELECT CLASS_INSTANCE_COUNT , CLASS_NAME
FROM MODEL_CLASS_COUNTS
WHERE TRUNC(COUNT_DATETIME) = TRUNC(SYSDATE)
)
LOOP
IF i.CLASS_INSTANCE_COUNT = 0
THEN
EMAIL('myemail#col.com',
'email header: ' || i.class_name || ' is 0',
'body: count for ' || i.class_name || ' is 0');
END IF;
END LOOP;
END;
Related
Question:
update tablename
set columnname = "12"
where columnname2 in ('1','2','3','4');
It will run with simple query.
How to run above query using a stored procedure i.e
update tablename
set columname = #param1
where columnname2 in (#param2);
where #param2 have '1','2' etc..
You should create a function which is used to delimit your comma seperated String..
CREATE FUNCTION SplitString
(
#Input NVARCHAR(MAX),
#Character CHAR(1)
)
RETURNS #Output TABLE (
Item NVARCHAR(1000)
)
AS
BEGIN
DECLARE #StartIndex INT, #EndIndex INT
SET #StartIndex = 1
IF SUBSTRING(#Input, LEN(#Input) - 1, LEN(#Input)) <> #Character
BEGIN
SET #Input = #Input + #Character
END
WHILE CHARINDEX(#Character, #Input) > 0
BEGIN
SET #EndIndex = CHARINDEX(#Character, #Input)
INSERT INTO #Output(Item)
SELECT SUBSTRING(#Input, #StartIndex, #EndIndex - 1)
SET #Input = SUBSTRING(#Input, #EndIndex + 1, LEN(#Input))
END
RETURN
END
GO
Now your update Query should be
Update tablename set columname=#param1
Where columnname2 in (SELECT Item FROM dbo.SplitString(#param2, ','))
I'm trying to do the things below in migration.
Split "Name" as splitted_name array.
SET first_name as splitted_name[0].
SET last_name as splitted_name[-1] if the splitted_name[0] and splitted_name[-1] were differnt.
SET last_name as empty string if the splitted_name[0] and splitted_name[1] are same.
Here is the code.
class ConvertNameIntoFirstAndLastName < ActiveRecord::Migration
def up
execute <<-SQL
DO
$do$
DECLARE
u record;
BEGIN
FOR u IN SELECT * FROM users LOOP
DECLARE
splitted_name text[];
BEGIN
splitted_name := CASE WHEN u.name IS NULL THEN '{''}'
ELSE regexp_split_to_array(u.name, E'\\s+')
END;
UPDATE users
SET
first_name = splitted_name[0],
last_name = CASE WHEN splitted_name[0] = splitted_name[-1] THEN ''
ELSE splitted_name[-1]
END,
name = splitted_name[0] || ' ' || (CASE WHEN splitted_name[0] = splitted_name[-1] THEN '{''}'
ELSE splitted_name[-1]
END)
WHERE id = u.id;
END;
END LOOP;
END;
$do$;
SQL
end
def down
end
end
The problem is u.name always return null when the name is unicode characters. The database encoding is set as Unicode.
Here is the error message.
PG::NotNullViolation: ERROR: null value in column "name" violates not-null constraint
=> The name is actually not null but some Unicode string.
Do you have any idea what is the cause of this error and how to solve this?
Sorry, I was so naive that I didn't know that I should use splitted_name[1] for the first_name and there's no array[-1].
This code worked.
class ConvertNameIntoFirstAndLastName < ActiveRecord::Migration
def up
execute <<-SQL
DO
$do$
DECLARE
u record;
BEGIN
FOR u IN SELECT * FROM users LOOP
DECLARE
splitted_name text[];
BEGIN
splitted_name := regexp_split_to_array(regexp_replace(u.name, ' ', ' '), ' ');
UPDATE users
SET
first_name = splitted_name[1],
last_name = CASE WHEN splitted_name[1] = splitted_name[array_upper(splitted_name, 1)] THEN ''
ELSE splitted_name[array_upper(splitted_name, 1)]
END,
name = splitted_name[1] || ' ' || (CASE WHEN splitted_name[1] = splitted_name[array_upper(splitted_name, 1)] THEN ''
ELSE splitted_name[array_upper(splitted_name, 1)]
END)
WHERE id = u.id;
END;
END LOOP;
END;
$do$;
SQL
end
def down
end
end
I have following Oracle stored procedure. Either subcode or stylecode is passed in. Currently it is update rows if value is not null. I want to add logic so that make update only if rows are exists on the table, if not, I like to print message like "The subcode xxxx doesn't exists" or "The stylecode xxxx doesn't exists". I don't think merge into works here.
create or replace PROCEDURE "REMOVE_PRICES"
(
RESULT OUT VARCHAR2
, STYLECODE_ IN NUMBER
, SUBCODE_ IN NUMBER
) AS
BEGIN
IF (SUBCODE_ is null AND STYLECODE_ is null)
THEN
raise_application_error(-20005, 'ERROR: Please provide either SUBCODE or STYLECODE!');
END IF;
IF SUBCODE_ IS NOT NULL THEN
UPDATE prices
SET type = null
WHERE subcode=SUBCODE_;
RESULT := SQL%ROWCOUNT || ' price for subcode ' || SUBCODE_ || ' is removed';
ELSIF STYLECODE_ IS NOT NULL THEN
UPDATE prices
SET type = null
WHERE stylecode=STYLECODE_;
RESULT := SQL%ROWCOUNT || ' price for stylecode ' || STYLECODE_ || ' is removed';
END IF;
END REMOVE_PRICES;
You can't only choose to do the update if it will affect rows unless you query with the same conditions first, doing a count; and you could still have a race condition with other sessions that means the data could change between the select and the update, unless you lock the rows. Which all seems a bit excessive and costly.
You can just check the value of SQL%ROWCOUNT and show that message if it is zero, or your current message otherwise:
IF SUBCODE_ IS NOT NULL THEN
UPDATE prices
SET type = null
WHERE subcode=SUBCODE_;
IF SQL%ROWCOUNT = 0 then
RESULT := 'The subcode ' || SUBCODE || ' does not exist';
ELSE
RESULT := SQL%ROWCOUNT || ' price for subcode ' || SUBCODE_ || ' is removed';
END IF;
ELSIF STYLECODE_ IS NOT NULL THEN
UPDATE prices
SET type = null
WHERE stylecode=STYLECODE_;
IF SQL%ROWCOUNT = 0 then
RESULT := 'The stylecode ' || STYLECODE || ' does not exist';
ELSE
RESULT := SQL%ROWCOUNT || ' price for stylecode ' || STYLECODE_ || ' is removed';
END IF;
END IF;
Hi i had a stored procedure as below,
Create PROCEDURE my_car(
in diesel integer,
out milege integer)
P1: BEGIN
SET START_query = 'SELECT*';
SET FROM_CLAUSE = ' FROM car, diesel';
SET WHERE_CLAUSE = ' WHERE car.c1 = diesel.c2';
IF (diesel =0) THEN
SET WHERE_CLAUSE = +WHERE_CLAUSE+'AND car.diesel=0' ;
ELSE
SET WHERE_CLAUSE = +WHERE_CLAUSE+' AND car.diesel='+diesel ;
END IF;
END P1
But its throwing error as below.
DB2 SQL Error: SQLCODE=-402, SQLSTATE=42819, SQLERRMC=+, DRIVER=3.52.90
and if we use || instead of +
ie.,
SET WHERE_CLAUSE = WHERE_CLAUSE || 'AND car.diesel=0' ;
then its throwing error as below,
DB2 SQL Error: SQLCODE=-440, SQLSTATE=42884, SQLERRMC=||;FUNCTION, DRIVER=3.52.90
please help on this.
In DB2, || rather than + is used for string concatenation.
Also, diesel is a character string and you are comparing it to zero. If you want diesel to be a 0 or 1 value, you should set its type to integer. If it needs to be a string, you should compare it to '' or '0' or whatever makes sense.
I'm not sure what you meant by +V_WHERE_CLAUSE+, but your code should look something like this:
IF (diesel = '0') THEN
SET WHERE_CLAUSE = WHERE_CLAUSE || 'AND car.diesel=0';
ELSE
SET WHERE_CLAUSE = WHERE_CLAUSE || ' AND car.diesel=' || diesel;
END IF;
Or maybe just this:
SET WHERE_CLAUSE = WHERE_CLAUSE || ' AND car.diesel=' || diesel;
When I parse through an email that looks like:
included_po~301993959 'VBCRLF
po_no~vendor~part_no~class~type_code~buyer~qty_ordered~measure~balance_on_order~cost~amt_ordered~order_date~delivery_date~ship_Date~receive_date~open~wo_no 'VBCRLF
301993959~100000~88008K~PROBE 800~F~VAX~4.0 ~EA~4.0~100.3300~401.32000~011513~012313~012313~000000~Y~STOCK 'VBCRLF
301993959~100000~TFCI-010-50~WIRE SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~STOCK 'VBCRLF
301993959~100000~TFIR-010-50~WIRE SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~STOCK 'VBCRLF
using code:
Public Sub AddItems()
Dim aLineItem() As String
Dim aItem() As String
Dim i As Integer
Dim j As Integer
Dim iCnt As Double
Dim msg
Dim Item As Items
ReDim sWo(0)
iCnt = 0
For i = 1 To UBound(sMsg())
aLineItem = Split(sMsg(i), vbCrLf)
For j = 1 To UBound(aLineItem)
If aLineItem(j) <> "" Then
If blah = 1 Then
Debug.Print ("...." & aLineItem(j))
End If
aItem = Split(aLineItem(j), "~")
If (aItem(0) <> "") And (aItem(0) <> "included_po") And (aItem(0) <> "po_no") Then
Item.PO_num = GetWo(aItem(1))
If Item.PO_num <> "0" Then
Item.Company = aItem(1)
Item.Delivery_date = aItem(12)
Item.pn = aItem(2)
Item.QTY_ordered = aItem(6)
Item.Unit_Price = aItem(9)
End If 'If Item.PO_num <> "0" Then
End If 'If aItem(1) <> "" Then
End If ' If aLineItem(j) <> "" Then
Next j
Next i
End Sub
The email parsing looks like this:
....301993959~100000~88008K~PROBE
....8800~F~VAX~4.0~EA~4.0~100.3300~401.32000~011513~012313~012313~000000~Y~S
....TOCK
Is there a better way to parse this email?
EDIT #1:
Public Sub GetMailMsg()
Dim pop3 As jmail.pop3
Dim iCount As Integer
Dim i As Integer
Dim mailID As Integer
Dim j As Integer
Dim sSubject As String
j = 0
ReDim sMsg(0)
'connect to the mail box
Set pop3 = New pop3
pop3.Connect "REMOVED FOR SECURITY"
'Get message count
iCount = pop3.Count
'Read Messages
For i = 1 To iCount
sSubject = pop3.Messages.Item(i).Subject
Label1.Caption = "Reading message.." & sSubject
DoEvents
If InStr(sSubject, "China Purchase Orders") <> 0 Then 'email test
j = j + 1
ReDim Preserve sMsg(j)
sMsg(j) = pop3.Messages.Item(i).Body
Label1.Caption = "Reading mail message for order " & sSubject
If blah = 1 Then
Debug.Print ("Reading mail message for order " & sSubject)
Debug.Print ("Reading mail message for order " & sMsg(j))
End If
End If
Next
pop3.Disconnect
Set pop3 = Nothing
End SUb
--EDIT #2
OUTPUT FROM DEBUG:
Reading mail message for order China Purchase Orders
Reading mail message for order
included_po~301993959
po_no~vendor~part_no~class~type_code~buyer~qty_ordered~measure~balance_o 'VBCRLF
n_order~cost~amt_ordered~order_date~delivery_date~ship_Date~receive_date 'VBCRLF
~open~wo_no 'VBCRLF
301993959~100000~88008K~PROBE 'VBCRLF
8800~F~VAX~4.0~EA~4.0~100.3300~401.32000~011513~012313~012313~000000~Y~S 'VBCRLF
TOCK 'VBCRLF
301993959~100000~TFCI-010-50~WIRE 'VBCRLF
SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~ST 'VBCRLF
OCK 'VBCRLF
301993959~100000~TFIR-010-50~WIRE 'VBCRLF
SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~ST 'VBCRLF
OCK 'VBCRLF
Your lines aren't breaking up properly makes me think there is a problem in the line aLineItem = Split(sMsg(i), vbCrLf). Please check whether you don't have any vbCrLF in the line you aren't getting right.
Is that line one continuous line?
Edit #1 # Jan 16, 2013 1:16pm EST:
I created a file and pasted provided input.
I created a simple program and incorporated your code into it. Please see produced DEBUG below, consisting as expected with 3 lines beginning with 301993959 and ending with STOCK. This is the correct and desirable output, right?
....301993959~100000~TFCI-010-50~WIRE SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~STOCK
....301993959~100000~TFIR-010-50~WIRE SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~STOCK
....301993959~100000~88008K~PROBE 800~F~VAX~4.0 ~EA~4.0~100.3300~401.32000~011513~012313~012313~000000~Y~STOCK
So the code you provided is working fine. If you say the input file is fine too, that means the issue is with how you are reading that email, specifically how you populate sMsg(). Can you post that code please?
Edit #2 # Jan 16, 2013 2:32pm EST:
You are getting some unwanted vbCrLfs in your single record line and you can't split it the way you want. Here is what I suggest you do:
1) If you can modify GetMailMsg to instead of loading Body as it is, go through line by line to avoid generating unwanted vbCrLfs. I have zero experience with pop objects so I don't know if that is possible.
2) If the number of unwanted cbCrLfs is consistent, ex: 2 in a single record, then you can simply adjust your code to concatenate split records like this
DIM concatLine As String
For j = 1 To UBound(aLineItem) Step 3
concatLine = aLineItem(j) & aLineItem(j+1) & aLineItem(j+2)
If concatLine <> "" Then
If blah = 1 Then
Debug.Print ("...." & concatLine)
End If
aItem = Split(concatLine, "~")
If (aItem(0) <> "") And (aItem(0) <> "included_po") And (aItem(0) <> "po_no") Then
Item.PO_num = GetWo(aItem(1))
If Item.PO_num <> "0" Then
Item.Company = aItem(1)
Item.Delivery_date = aItem(12)
Item.pn = aItem(2)
Item.QTY_ordered = aItem(6)
Item.Unit_Price = aItem(9)
End If 'If Item.PO_num <> "0" Then
End If 'If aItem(1) <> "" Then
End If ' If concatLine <> "" Then
Next j
3) or better yet, concat string until you reach the end of the record and then split that concatenated string.
DIM concatLine As String
DIM detailsRecord as Integer
For detailsRecord = 1 To UBound(aLineItem)
if LCase(Right(aLineItem(detailsRecord),5)) = 'wo_no' Then Exit For ' when we find this tag, we know where details record begin
Next detailsRecord
For j = detailsRecord + 1 To UBound(aLineItem) ' begin looping detail records
concatLine = concatLine + aLineItem(j)
If UCase(Right(aLineItem(j), 5)) = "STOCK" Then ' this is your end of the record indicator
If blah = 1 Then
Debug.Print ("...." & concatLine)
End If
aItem = Split(concatLine, "~")
If (aItem(0) <> "") Then
Item.PO_num = GetWo(aItem(1))
If Item.PO_num <> "0" Then
Item.Company = aItem(1)
Item.Delivery_date = aItem(12)
Item.pn = aItem(2)
Item.QTY_ordered = aItem(6)
Item.Unit_Price = aItem(9)
End If 'If Item.PO_num <> "0" Then
End If 'If aItem(1) <> "" Then
End If ' If concatLine <> "" Then
concatLine = ""
Next j
For cases 2 and 3, don't forget to handle the headers first- you will have to move If (aItem(0) <> "") And (aItem(0) <> "included_po") And (aItem(0) <> "po_no") outside the main loop to handle header records (i believe the first 2 or records are headers).
EDIT #3:
I fixed scenario #3 to skip through the header records (assuming 'wo_no' is an indicator of the end of that record), then to concatenate strings to form a single record by searching for an end tag ("STOCK"). This method is going to be flexible enough to handle dynamic number of vbCrLfs in the email body that splits a single record into unpredictable number of strings.
The code was typed in the browser, so I don't guarantee it will work :)
Since you know what should start each line, then use the Split function using "301993959".
Dim LineItems(100) As String
x = Split(sMsg(i), "301993959")
For j = 1 To UBound(x) - 1 'Don't use 0 becuase you don't need that part
LineItems(j - 1) = x(j)
Next i
Of Course you could take it one step further by then splitting each item in the string using "~" as your second delimiter.
Dim LineItems(100, 15) As String
x = Split(Text1.Text, "301993959")
For j = 1 To UBound(x) - 1 'Don't use 0 becuase you don't need that part
y = Split(x(j), "~")
For k = 1 To 15
LineItems(j - 1, k) = y(k)
Next k
Next j