Converting NDCs from 10-digits to 11 digits in sql when bulkinsert - ndc

need to convert NDCs codes from 10-digits to 11 digits. in sql server

[NDCPACKAGECODE]=(
CASE CHARINDEX('-', [NDCPACKAGECODE])
WHEN 5 THEN
REPLACE('0'+SUBSTRING([NDCPACKAGECODE],CHARINDEX('', [NDCPACKAGECODE]), LEN([NDCPACKAGECODE])+1), '-', '')
WHEN 6 THEN
CASE (CHARINDEX('-', REVERSE([NDCPACKAGECODE])))
WHEN 3 THEN
REPLACE(LEFT([NDCPACKAGECODE], (CHARINDEX('-', [NDCPACKAGECODE])))+'0'+SUBSTRING([NDCPACKAGECODE], CHARINDEX('-', [NDCPACKAGECODE])+1, LEN([NDCPACKAGECODE])), '-', '')
WHEN 2 THEN
REPLACE(STUFF([NDCPACKAGECODE], LEN([NDCPACKAGECODE])- CHARINDEX('-', REVERSE([NDCPACKAGECODE]))+1, 1, '0'), '-', '')
END
END
)

In case anyone is curious, this is the MySQL version of this.
select
ndc_package_code,
replace((
case locate('-', ndc_package_code)
when 5 then
concat(0, ndc_package_code)
when 6 then
case (locate('-', reverse(ndc_package_code)))
when 3 then
concat(
left(ndc_package_code, locate('-', ndc_package_code)),
concat(0, substring(ndc_package_code, locate('-', ndc_package_code) + 1, length(ndc_package_code)))
)
when 2 then
concat(left(ndc_package_code, length(ndc_package_code) - 1), '0', right(ndc_package_code, 1))
end
end
), '-', '') as normalized_code
from drugs

A Postgres version (populating a normalized_code field in a packages table)
UPDATE packages
SET normalized_code = REPLACE((
CASE POSITION('-' IN ndc_package_code)
when 5 then
CONCAT(0, ndc_package_code)
WHEN 6 THEN
CASE (POSITION('-' IN REVERSE(ndc_package_code)))
WHEN 3 THEN
CONCAT(
LEFT(ndc_package_code, POSITION('-' IN ndc_package_code)),
CONCAT(0, SUBSTRING(ndc_package_code, POSITION('-' IN ndc_package_code) + 1, LENGTH(ndc_package_code)))
)
WHEN 2 THEN
CONCAT(LEFT(ndc_package_code, LENGTH(ndc_package_code) - 1), '0', RIGHT(ndc_package_code, 1))
END
END
), '-', '')
;

Related

How to pass multiple OR and AND condition in Activate Record in Rails as a string

I'm new in Ruby on rails and I would like to fetch records based on a condition, and I'm passing the condition in a string format. Moreover, I will pass the query in multiple OR and AND conditions. However, right now, I'm stuck that how to pass the query in string format in rails
I have attached the screenshot
#data= CustomAttribute.includes(:custom_attribute_values).where(id: 18, company_id: current_user.company_id).first
The above line executed successfully and gave the output
<CustomAttribute id: 18, data_type: "string", label: "Marital status", code: "marital_status", entity_type: "member", company_id: 1, created_at: "2021-03-10 10:16:15", updated_at: "2021-03-10 10:16:27", is_active: true, is_default: false, rank: nil, is_identifier: false>
but when I executed the below line it gave me the error that
#data.custom_attribute_values.where("\""+"value_string"+"\""+"="+"\""+'Single'+"\"").size
ERROR: column "Single" does not exist
the Single is the value which I would like to count
Here is my code for the dynamic query creation
logical_operator = 'OR'
#custom_attribute = CustomAttribute.includes(:custom_attribute_values).where(id: custom_attribute_ids, company_id: current_user.company_id)
query=""
#custom_attribute.each_with_index do |attribute_object, index|
filter_object= filter_params[:filters].find {|x| x['custom_attribute_id']==attribute_object['id']}
if filter_object.present?
query += "("+ '"' +'value_'+attribute_object.data_type + '"' + ' ' + filter_object['operator'] + ' ' + "'" + filter_object['value'].to_s + "'"+ ")"
end
if index != #custom_attribute.length-1
query+=' '+logical_operator+' '
end
if index == #custom_attribute.length-1
query="'" + " ( " + query + " ) " + "'"
end
end
byebug
puts(#custom_attribute.first.custom_attribute_values.where(query).size)
Any time you're doing a lot of escaping and string addition in Ruby you're doing it wrong. If we clean up how you build your SQL:
"\""+"value_string"+"\""+"="+"\""+'Single'+"\""
things will be clearer. First, put space around your operators for readability:
"\"" + "value_string" + "\"" + "=" + "\"" + 'Single' + "\""
Next, don't use double quotes unless you need them for escape codes (such as \n) or interpolation:
'"' + 'value_string' + '"' + '=' + '"' + 'Single' + '"'
Now we see that we're adding several constant strings so there's no need to add them at all, a single string literal will do:
'"value_string" = "Single"'
Standard SQL uses double quotes for identifiers (such as table and column names) and single quotes for strings. So your query is asking for all rows where the value_string column equals the Single column and there's your error.
You want to use single quotes for the string (and %q(...) to quote the whole thing to avoid adding escapes back in):
#data.custom_attribute_values.where(
%q("value_string" = 'Single')
)
Or better, let ActiveRecord build the query:
# With a positional placeholder:
#data.custom_attribute_values.where('value_string = ?', 'Single')
# Or a named placeholder:
#data.custom_attribute_values.where('value_string = :s', s: 'Single')
# Or most idiomatic:
#data.custom_attribute_values.where(value_string: 'Single')

Splitting/Slicing array in ruby

I've found this similar two questions to the one I'm about to ask:
Split array up into n-groups of m size?
and
Need to split arrays to sub arrays of specified size in Ruby
This splits array into three arrays with each array having three elements :
a.each_slice(3) do |x,y,z|
p [x,y,z]
end
So if I do this (my array size is 1000) :
a.each_slice(200) do |a,b,c,d,e|
p "#{a} #{b} #{c} #{d} #{e}"
end
This should split my array into 5 arrays each having 200 members? But it doesn't?
What I actually need to do is to put 200 random elements into 5 arrays, am I on the right track here, how can I do this?
Enumerable#each_slice
If you provide a single argument to the block of each_slice then it will fill that argument with an array of values less than or equal to the given argument. On the last iteration if there are less than n values left then the array size will be whatever is left.
If you provide multiple arguments to the block of each_slice then it will fill those values with the values from the source array. If the slice size is greater than the number of arguments given then some values will be ignored. If it is less than the number of arguments than the excess arguments will be nil.
a = (1..9).to_a
a.each_slice(3) {|b| puts b.inspect }
[1,2,3]
[4,5,6]
[7,8,9]
a.each_slice(4) {|b| puts b.inspect }
[1,2,3,4]
[5,6,7,8]
[9]
a.each_slice(3) {|b,c,d| puts (b + c + d)}
6 # 1 + 2 + 3
15 # 4 + 5 + 6
24 # 7 + 8 + 9
a.each_slice(3) {|b,c| puts (b + c)}
3 # 1 + 2, skips 3
9 # 4 + 5, skips 6
15 # 7 + 8, skips 9
a.each_slice(2) {|b,c| puts c.inspect}
2
4
6
8
nil
a.each_slice(3) {|b,c,d,e| puts e.inspect}
nil
nil
nil
irb(main):001:0> a= (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):002:0> a.sample(3)
=> [5, 10, 1]
irb(main):003:0> (1..3).map{ a.sample(3) }
=> [[6, 2, 5], [8, 7, 3], [4, 5, 7]]
irb(main):004:0>
Actually you will return a string with the five elements inserted in it.
You can try something:
a1 = [], a2 = [], a3 = [], a4 = [], a5 = []
a.each_slice(5) do |a,b,c,d,e|
a1 << a
a2 << b
a3 << c
a4 << d
a5 << e
end
You will end up with five arrays containing 200 elements each.
I used the simplest possible syntax to make it clear, you can
make it much more condensed.
If you want to assign that result to 5 different arrays, you could use the splat operator,like this:
a,b,c,d,e = *(1..1000).each_slice(200).to_a

How can I get the table description (fields and types) from Firebird with dbExpress

I have written a tool for displaying database structures using the GetTableNames and GetFieldNames methods of TSQLConnection. How can I get the types of each field name similar to the following list (which is part of the DDL required to build the table)?
TABLE: ARTICLES
ID INTEGER NOT NULL
PRINTED SMALLINT DEFAULT 0
ACADEMIC SMALLINT
RELEVANCE SMALLINT
SOURCE VARCHAR(64) CHARACTER SET WIN1251 COLLATE WIN1251
NAME VARCHAR(128) CHARACTER SET WIN1251 COLLATE WIN1251
FILENAME VARCHAR(128) CHARACTER SET WIN1251 COLLATE WIN1251
NOTES VARCHAR(2048) CHARACTER SET WIN1251 COLLATE WIN1251
This is incomplete (because I've never used Firebird array data types) and not much tested but perhaps it will give you a good starting point:
SELECT
RF.RDB$FIELD_NAME FIELD_NAME,
CASE F.RDB$FIELD_TYPE
WHEN 7 THEN
CASE F.RDB$FIELD_SUB_TYPE
WHEN 0 THEN 'SMALLINT'
WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
WHEN 2 THEN 'DECIMAL'
END
WHEN 8 THEN
CASE F.RDB$FIELD_SUB_TYPE
WHEN 0 THEN 'INTEGER'
WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
WHEN 2 THEN 'DECIMAL'
END
WHEN 9 THEN 'QUAD'
WHEN 10 THEN 'FLOAT'
WHEN 12 THEN 'DATE'
WHEN 13 THEN 'TIME'
WHEN 14 THEN 'CHAR(' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ') '
WHEN 16 THEN
CASE F.RDB$FIELD_SUB_TYPE
WHEN 0 THEN 'BIGINT'
WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
WHEN 2 THEN 'DECIMAL'
END
WHEN 27 THEN 'DOUBLE'
WHEN 35 THEN 'TIMESTAMP'
WHEN 37 THEN 'VARCHAR(' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ')'
WHEN 40 THEN 'CSTRING' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ')'
WHEN 45 THEN 'BLOB_ID'
WHEN 261 THEN 'BLOB SUB_TYPE ' || F.RDB$FIELD_SUB_TYPE
ELSE 'RDB$FIELD_TYPE: ' || F.RDB$FIELD_TYPE || '?'
END FIELD_TYPE,
IIF(COALESCE(RF.RDB$NULL_FLAG, 0) = 0, NULL, 'NOT NULL') FIELD_NULL,
CH.RDB$CHARACTER_SET_NAME FIELD_CHARSET,
DCO.RDB$COLLATION_NAME FIELD_COLLATION,
COALESCE(RF.RDB$DEFAULT_SOURCE, F.RDB$DEFAULT_SOURCE) FIELD_DEFAULT,
F.RDB$VALIDATION_SOURCE FIELD_CHECK,
RF.RDB$DESCRIPTION FIELD_DESCRIPTION
FROM RDB$RELATION_FIELDS RF
JOIN RDB$FIELDS F ON (F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE)
LEFT OUTER JOIN RDB$CHARACTER_SETS CH ON (CH.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID)
LEFT OUTER JOIN RDB$COLLATIONS DCO ON ((DCO.RDB$COLLATION_ID = F.RDB$COLLATION_ID) AND (DCO.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID))
WHERE (RF.RDB$RELATION_NAME = :TABLE_NAME) AND (COALESCE(RF.RDB$SYSTEM_FLAG, 0) = 0)
ORDER BY RF.RDB$FIELD_POSITION;
Use direct access to RDB$ tables. For example:
SELECT * FROM rdb$relations
will give you a list of all tables in a database.
SELECT
*
FROM
rdb$relation_fields rf JOIN rdb$fields f
ON f.rdb$field_name = rf.rdb$field_source
WHERE
rf.rdb$relation_name = :RN
will result in a list of all fields of given table
with information of field type. Param RN is a name of the table.
Using information from RDB$tables one can easily construct DDL
statement. The query below gives you a hint how to do it:
SELECT
TRIM(rf.rdb$field_name) || ' ' ||
IIF(rdb$field_source LIKE 'RDB$%',
DECODE(f.rdb$field_type,
8, 'INTEGER',
12, 'DATE',
37, 'VARCHAR',
14, 'CHAR',
7, 'SMALLINT'),
TRIM(rdb$field_source)) ||
IIF((rdb$field_source LIKE 'RDB$%') AND (f.rdb$field_type IN (37, 14)),
'(' || f.rdb$field_length || ')',
'') ||
IIF((f.rdb$null_flag = 1) OR (rf.rdb$null_flag = 1),
' NOT NULL', '')
FROM
rdb$relation_fields rf JOIN rdb$fields f
ON f.rdb$field_name = rf.rdb$field_source
WHERE
rf.rdb$relation_name = '<put_your_table_name_here>'
Using the link which TLama provided, I found my own solution, which is somewhat similar to the above solutions, but simpler.
SELECT R.RDB$FIELD_NAME AS field_name,
CASE F.RDB$FIELD_TYPE
WHEN 7 THEN 'SMALLINT'
WHEN 8 THEN 'INTEGER'
WHEN 9 THEN 'QUAD'
WHEN 10 THEN 'FLOAT'
WHEN 11 THEN 'D_FLOAT'
WHEN 12 THEN 'DATE'
WHEN 13 THEN 'TIME'
WHEN 14 THEN 'CHAR'
WHEN 16 THEN 'INT64'
WHEN 27 THEN 'DOUBLE'
WHEN 35 THEN 'TIMESTAMP'
WHEN 37 THEN 'VARCHAR'
WHEN 40 THEN 'CSTRING'
WHEN 261 THEN 'BLOB'
ELSE 'UNKNOWN'
END AS field_type,
F.RDB$FIELD_LENGTH AS field_length,
CSET.RDB$CHARACTER_SET_NAME AS field_charset
FROM RDB$RELATION_FIELDS R
LEFT JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME
LEFT JOIN RDB$CHARACTER_SETS CSET ON F.RDB$CHARACTER_SET_ID = CSET.RDB$CHARACTER_SET_ID
WHERE R.RDB$RELATION_NAME= :p1
ORDER BY R.RDB$FIELD_POSITION
p1 is the table name which is passed as a parameter to the query.
In context, I have a treeview which has as its nodes the table names of a given database; for each node, the child nodes are the fields along with their definitions.
sqlcon.GetTableNames (dbTables); // sqlcon is the TSQLConnection
tv.items.Clear;
for i:= 1 to dbTables.count do
begin
node:= tv.items.Add (nil, dbTables[i - 1]);
with qFields do // the above query
begin
params[0].asstring:= dbTables[i - 1];
open;
while not eof do
begin
tv.items.addchild (node, trim (fieldbyname ('field_name').asstring) + ', ' +
trim (fieldbyname ('field_type').asstring) + ', ' +
fieldbyname ('field_length').asstring + ', ' +
fieldbyname ('field_charset').asstring);
next
end;
close
end
end;
Here is a screenshot of the program in action. I realise that the format is not the same as the DDL which I quoted, but it's obvious what each field means (at least to me, and this is a program for my private use).
I made a litle change to the first option to support computed by fields, add field_position and made a view to make more easy.
CREATE VIEW TABLES (
TABLE_NAME,
FIELD_NAME,
FIELD_POSITION,
FIELD_TYPE,
FIELD_NULL,
FIELD_CHARSET,
FIELD_COLLATION,
FIELD_DEFAULT,
FIELD_CHECK,
FIELD_DESCRIPTION
)
AS
SELECT
RF.RDB$RELATION_NAME,
RF.RDB$FIELD_NAME FIELD_NAME,
RF.RDB$FIELD_POSITION FIELD_POSITION,
CASE F.RDB$FIELD_TYPE
WHEN 7 THEN
CASE F.RDB$FIELD_SUB_TYPE
WHEN 0 THEN 'SMALLINT'
WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
WHEN 2 THEN 'DECIMAL'
END
WHEN 8 THEN
CASE F.RDB$FIELD_SUB_TYPE
WHEN 0 THEN 'INTEGER'
WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
WHEN 2 THEN 'DECIMAL'
END
WHEN 9 THEN 'QUAD'
WHEN 10 THEN 'FLOAT'
WHEN 12 THEN 'DATE'
WHEN 13 THEN 'TIME'
WHEN 14 THEN 'CHAR(' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ') '
WHEN 16 THEN
CASE F.RDB$FIELD_SUB_TYPE
WHEN 0 THEN 'BIGINT'
WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
WHEN 2 THEN 'DECIMAL'
END
WHEN 27 THEN 'DOUBLE'
WHEN 35 THEN 'TIMESTAMP'
WHEN 37 THEN
IIF (COALESCE(f.RDB$COMPUTED_SOURCE,'')<>'',
'COMPUTED BY ' || CAST(f.RDB$COMPUTED_SOURCE AS VARCHAR(250)),
'VARCHAR(' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ')')
WHEN 40 THEN 'CSTRING' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ')'
WHEN 45 THEN 'BLOB_ID'
WHEN 261 THEN 'BLOB SUB_TYPE ' || F.RDB$FIELD_SUB_TYPE
ELSE 'RDB$FIELD_TYPE: ' || F.RDB$FIELD_TYPE || '?'
END FIELD_TYPE,
IIF(COALESCE(RF.RDB$NULL_FLAG, 0) = 0, NULL, 'NOT NULL') FIELD_NULL,
CH.RDB$CHARACTER_SET_NAME FIELD_CHARSET,
DCO.RDB$COLLATION_NAME FIELD_COLLATION,
COALESCE(RF.RDB$DEFAULT_SOURCE, F.RDB$DEFAULT_SOURCE) FIELD_DEFAULT,
F.RDB$VALIDATION_SOURCE FIELD_CHECK,
RF.RDB$DESCRIPTION FIELD_DESCRIPTION
FROM RDB$RELATION_FIELDS RF
JOIN RDB$FIELDS F ON (F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE)
LEFT OUTER JOIN RDB$CHARACTER_SETS CH ON (CH.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID)
LEFT OUTER JOIN RDB$COLLATIONS DCO ON ((DCO.RDB$COLLATION_ID = F.RDB$COLLATION_ID) AND (DCO.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID))
WHERE (COALESCE(RF.RDB$SYSTEM_FLAG, 0) = 0)
ORDER BY RF.RDB$FIELD_POSITION
;

Dynamic Relational operator in a where clause is Invalid (PL/SQL Oracle)

I am using Oracle 10g and I have the following stored procedure:
CREATE OR REPLACE PACKAGE BODY RF_PKG_STFCA_PositivePay
AS
PROCEDURE RF_SP_STFCA_PositivePay(IN_DATE IN NUMBER, IN_DATE_OPERATOR IN NVARCHAR2, OUT_DATA OUT CUR_DATA)
IS
/* this procedure returns a Ref Cursor with all the requested parameters
calling the stored procedure from an asp page (and anywhere else)
does not require posting a predefined number of records */
PaymentBatchNumber NVARCHAR2(4);
CurrencyCode NVARCHAR2(3);
TransactionCode NVARCHAR2(3);
Transit_BranchNumber NVARCHAR2(5);
BankAccountNumber NVARCHAR2(7);
ChequeNumber NVARCHAR2(8);
ChequeAmount NVARCHAR2(10);
ClientReference NVARCHAR2(19);
IssueDate NVARCHAR2(8);
PayeeName1 NVARCHAR2(60);
AddressLine1 NVARCHAR2(60);
AddressLine2 NVARCHAR2(60);
AddressLine4 NVARCHAR2(60);
AddressLine5 NVARCHAR2(60);
DateCreated NVARCHAR2(25);
DateVoided NVARCHAR2(25);
BEGIN
OPEN OUT_DATA FOR
SELECT LPAD(NVL(CD.PAYMENT_BATCH_NO, '0'), 4, '0') AS PaymentBatchNumber,
SUBSTR(NVL(CD.CURRENCY_ID, ' '), 1, 1) AS CurrencyCode,
NVL(CD.STATUS, ' ') AS TransactionCode,
LPAD(NVL(BA.BRANCH_ID, '0'), 5, '0') AS Transit_BranchNumber,
LPAD(NVL(BA.ACCOUNT_NO, '0'), 7, '0') AS BankAccountNumber,
LPAD(NVL(CD.CHECK_NO, '0') , 8, '0') AS ChequeNumber,
LPAD(TO_CHAR(NVL(CD.AMOUNT, 0)), 10, '0') AS ChequeAmount,
LPAD(NVL(CD.CONTROL_NO, '0'), 19, '0') AS ClientReference,
TO_CHAR(NVL(CD.CHECK_DATE, LPAD(' ', 8, ' ')), 'YYYYMMDD') AS IssueDate,
RPAD(NVL(CD.NAME, ' '), 60, ' ') AS PayeeName1,
RPAD(NVL(CD.ADDR_1, ' '), 60, ' ') AS AddressLine1,
RPAD(NVL(CD.ADDR_2, ' '), 60, ' ') AS AddressLine2,
RPAD(NVL(CD.CITY, '') || CASE WHEN CD.CITY IS NULL OR CD.STATE IS NULL THEN ' ' ELSE ', ' END || NVL(CD.STATE, ''), 60, ' ') AS AddressLine4,
RPAD(NVL(CD.ZIPCODE, ' '), 60, ' ') AS AddressLine5,
TO_CHAR(CD.CREATE_DATE, 'YYYYMMDDHH24MISS') AS DateCreated,
CASE WHEN CD.VOID_DATE IS NULL THEN ' ' ELSE TO_CHAR(CD.VOID_DATE, 'YYYYMMDDHH24MISS') END AS DateVoided
INTO PaymentBatchNumber, CurrencyCode, TransactionCode, Transit_BranchNumber, BankAccountNumber, ChequeNumber,
ChequeAmount, ClientReference, IssueDate, PayeeName1, AddressLine1, AddressLine2, AddressLine4, AddressLine5,
DateCreated, DateVoided
FROM BANK_ACCOUNT BA
INNER JOIN CASH_DISBURSEMENT CD ON BA.ID = CD.BANK_ACCOUNT_ID
WHERE BA.ACCOUNT_NO IS NOT NULL AND CD.CHECK_NO > 0 AND CD.STATUS != 'X' AND CD.AMOUNT != 0 AND ((TO_NUMBER(TO_CHAR(CD.CREATE_DATE, 'YYYYMMDDHH24MISS')) || IN_DATE_OPERATOR || IN_DATE) OR
(CASE WHEN CD.VOID_DATE IS NULL THEN 0 ELSE TO_NUMBER(TO_CHAR(CD.VOID_DATE, 'YYYYMMDDHH24MISS')) END || IN_DATE_OPERATOR || IN_DATE))
ORDER BY BA.BRANCH_ID, BA.ACCOUNT_NO;
END RF_SP_STFCA_PositivePay;
END RF_PKG_STFCA_PositivePay;
And I get the following error when entering this into SQL plus:
invalid relational operator
What I'm trying to do: I have this stored procedure that returns a secordset to my asp.net application using the REF CURSOR. I give it 2 input parameters. 1 is a date (IN_DATE) and 1 is an operator (IN_DATE_OPERATOR). The program works if "|| IN_DATE_OPERATOR ||" is replaces with either = or >= just the way I want it to work. The problem is based on what happens in the .Net application I want the operater it uses in the where clause to be either ">=" or "=" and I wont know which until runtime.
I know I'm doing this wrong but I don't know how to get oracle to reconize that IN_DATE_OPERATOR is a relational operator. I am open to other methods to have a dynamic operator (i tried CASE WHEN IN_DATE_OPERATOR = '=' THEN '=' ELSE '>=' END to no avail too) but I don't want to create a whole seperate stored procedure I will have to maintin in addition to this or a completely dynamic where clause. My ideal solution would make the least amount of changes to this query as possible. Any suggestions?
Edit: ok I've edited my query do be the following:
CREATE OR REPLACE PACKAGE BODY RF_PKG_STFCA_PositivePay
AS
PROCEDURE RF_SP_STFCA_PositivePay(IN_DATE IN NUMBER, IN_DATE_OPERATOR IN VARCHAR2, OUT_DATA OUT CUR_DATA)
IS
/* this procedure returns a Ref Cursor with all the requested parameters
calling the stored procedure from an asp page (and anywhere else)
does not require posting a predefined number of records */
SQL_Statement VARCHAR2(8000);
BEGIN
SQL_Statement := 'SELECT LPAD(NVL(CD.PAYMENT_BATCH_NO, ''0''), 4, ''0'') AS PaymentBatchNumber, ' ||
' SUBSTR(NVL(CD.CURRENCY_ID, '' ''), 1, 1) AS CurrencyCode, ' ||
' NVL(CD.STATUS, '' '') AS TransactionCode, ' ||
' LPAD(NVL(BA.BRANCH_ID, ''0''), 5, ''0'') AS Transit_BranchNumber, ' ||
' LPAD(NVL(BA.ACCOUNT_NO, ''0''), 7, ''0'') AS BankAccountNumber, ' ||
' LPAD(NVL(CD.CHECK_NO, ''0'') , 8, ''0'') AS ChequeNumber, ' ||
' LPAD(TO_CHAR(NVL(CD.AMOUNT, 0)), 10, ''0'') AS ChequeAmount, ' ||
' LPAD(NVL(CD.CONTROL_NO, ''0''), 19, ''0'') AS ClientReference, ' ||
' TO_CHAR(NVL(CD.CHECK_DATE, LPAD('' '', 8, '' '')), ''YYYYMMDD'') AS IssueDate, ' ||
' RPAD(NVL(CD.NAME, '' ''), 60, '' '') AS PayeeName1, ' ||
' RPAD(NVL(CD.ADDR_1, '' ''), 60, '' '') AS AddressLine1, ' ||
' RPAD(NVL(CD.ADDR_2, '' ''), 60, '' '') AS AddressLine2, ' ||
' RPAD(NVL(CD.CITY, '''') || CASE WHEN CD.CITY IS NULL OR CD.STATE IS NULL THEN '' '' ELSE '', '' END || NVL(CD.STATE, ''''), 60, '' '') AS AddressLine4, ' ||
' RPAD(NVL(CD.ZIPCODE, '' ''), 60, '' '') AS AddressLine5, ' ||
' TO_CHAR(CD.CREATE_DATE, ''YYYYMMDDHH24MISS'') AS DateCreated, ' ||
' CASE WHEN CD.VOID_DATE IS NULL THEN '' '' ELSE TO_CHAR(CD.VOID_DATE, ''YYYYMMDDHH24MISS'') END AS DateVoided ' ||
' FROM BANK_ACCOUNT BA ' ||
' INNER JOIN CASH_DISBURSEMENT CD ON BA.ID = CD.BANK_ACCOUNT_ID ' ||
' WHERE BA.ACCOUNT_NO IS NOT NULL AND CD.CHECK_NO > 0 AND CD.STATUS != ''X'' AND CD.AMOUNT != 0 ' ||
' AND ((TO_NUMBER(TO_CHAR(CD.CREATE_DATE, ''YYYYMMDDHH24MISS'')) ' || IN_DATE_OPERATOR || ' :1) ' ||
' OR (CASE WHEN CD.VOID_DATE IS NULL THEN 0 ELSE TO_NUMBER(TO_CHAR(CD.VOID_DATE, ''YYYYMMDDHH24MISS'')) END ' || IN_DATE_OPERATOR || ' :2)) ' ||
' ORDER BY BA.BRANCH_ID, BA.ACCOUNT_NO ';
OPEN OUT_DATA FOR SQL_Statement USING IN_DATE, IN_DATE;
END RF_SP_STFCA_PositivePay;
END RF_PKG_STFCA_PositivePay;/
but I get the following error:
LINE/COL ERROR
32/3 PL/SQL: Statement ignored
32/21 PLS-00382: expression is of wrong type
You would need to dynamically assemble the SQL statement in a string and then use that string to open the cursor. You'll need something along the lines of the get_cur procedure below where you assemble the SQL statement in a local VARCHAR2 variable including the placeholders for the bind variables and then open the cursor using the SQL statement you assembled and the bind variable you passed in.
SQL> create or replace procedure get_cur( p_date in date, p_operator in varchar2, p_cur out sys_refcursor )
2 as
3 l_sql_stmt varchar2(1000);
4 begin
5 l_sql_stmt := 'select * from emp where hiredate ' || p_operator || ' :1';
6 open p_cur for l_sql_stmt using p_date;
7 end;
8 /
Procedure created.
SQL> var rc refcursor;
SQL> exec get_cur( date '2001-01-01', '>=', :rc );
PL/SQL procedure successfully completed.
SQL> print rc;
no rows selected
SQL> exec get_cur( date '2001-01-01', '<=', :rc );
PL/SQL procedure successfully completed.
SQL> print rc;
EMPNO ENAME JOB MGR HIREDATE SAL COMM
---------- ---------- --------- ---------- --------- ---------- ----------
DEPTNO
----------
7369 SMITH CLERK 7902 17-DEC-80 801
20
7499 ALLEN SALESMAN 7698 20-FEB-81 1601 300
30
7521 WARD SALESMAN 7698 22-FEB-81 1251 500
30
EMPNO ENAME JOB MGR HIREDATE SAL COMM
---------- ---------- --------- ---------- --------- ---------- ----------
DEPTNO
----------
7566 JONES MANAGER 7839 02-APR-81 2976
20
7654 MARTIN SALESMAN 7698 28-SEP-81 1251 1400
30
7698 BLAKE MANAGER 7839 01-MAY-81 2851
30
EMPNO ENAME JOB MGR HIREDATE SAL COMM
---------- ---------- --------- ---------- --------- ---------- ----------
DEPTNO
----------
7782 CLARK MANAGER 7839 09-JUN-81 2451
10
7788 SCOTT ANALYST 7566 19-APR-87 3001
20
7839 KING PRESIDENT 17-NOV-81 5001
10
EMPNO ENAME JOB MGR HIREDATE SAL COMM
---------- ---------- --------- ---------- --------- ---------- ----------
DEPTNO
----------
7844 TURNER SALESMAN 7698 08-SEP-81 1501 0
30
7876 ADAMS CLERK 7788 23-MAY-87 1101
20
7900 JAMES CLERK 7698 03-DEC-81 951
30
EMPNO ENAME JOB MGR HIREDATE SAL COMM
---------- ---------- --------- ---------- --------- ---------- ----------
DEPTNO
----------
7902 FORD ANALYST 7566 03-DEC-81 3001
20
7934 MILLER CLERK 7782 23-JAN-82 1301
10
14 rows selected.
My guess is that you want something like this (obviously, since I don't have your tables or types, I can't test that this actually compiles so you'll likely need to correct typos)
CREATE OR REPLACE PACKAGE BODY RF_PKG_STFCA_PositivePay
AS
PROCEDURE RF_SP_STFCA_PositivePay(IN_DATE IN NUMBER, IN_DATE_OPERATOR IN NVARCHAR2, OUT_DATA OUT CUR_DATA)
IS
/* this procedure returns a Ref Cursor with all the requested parameters
calling the stored procedure from an asp page (and anywhere else)
does not require posting a predefined number of records */
l_sql_stmt VARCHAR2(4000);
BEGIN
l_sql_stmt := q'[SELECT LPAD(NVL(CD.PAYMENT_BATCH_NO, '0'), 4, '0') AS PaymentBatchNumber, ]' ||
q'[SUBSTR(NVL(CD.CURRENCY_ID, ' '), 1, 1) AS CurrencyCode, ]' ||
q'[NVL(CD.STATUS, ' ') AS TransactionCode, ]' ||
q'[LPAD(NVL(BA.BRANCH_ID, '0'), 5, '0') AS Transit_BranchNumber, ]' ||
q'[LPAD(NVL(BA.ACCOUNT_NO, '0'), 7, '0') AS BankAccountNumber, ]' ||
q'[LPAD(NVL(CD.CHECK_NO, '0') , 8, '0') AS ChequeNumber, ]' ||
q'[LPAD(TO_CHAR(NVL(CD.AMOUNT, 0)), 10, '0') AS ChequeAmount, ]' ||
q'[LPAD(NVL(CD.CONTROL_NO, '0'), 19, '0') AS ClientReference, ]' ||
q'[TO_CHAR(NVL(CD.CHECK_DATE, LPAD(' ', 8, ' ')), 'YYYYMMDD') AS IssueDate, ]' ||
q'[RPAD(NVL(CD.NAME, ' '), 60, ' ') AS PayeeName1, ]' ||
q'[RPAD(NVL(CD.ADDR_1, ' '), 60, ' ') AS AddressLine1, ]' ||
q'[RPAD(NVL(CD.ADDR_2, ' '), 60, ' ') AS AddressLine2, ]' ||
q'[RPAD(NVL(CD.CITY, '') || CASE WHEN CD.CITY IS NULL OR CD.STATE IS NULL THEN ' ' ELSE ', ' END || NVL(CD.STATE, ''), 60, ' ') AS AddressLine4, ]' ||
q'[RPAD(NVL(CD.ZIPCODE, ' '), 60, ' ') AS AddressLine5, ]' ||
q'[TO_CHAR(CD.CREATE_DATE, 'YYYYMMDDHH24MISS') AS DateCreated, ]' ||
q'[CASE WHEN CD.VOID_DATE IS NULL THEN ' ' ELSE TO_CHAR(CD.VOID_DATE, 'YYYYMMDDHH24MISS') END AS DateVoided ]' ||
q'[FROM BANK_ACCOUNT BA ]' ||
q'[INNER JOIN CASH_DISBURSEMENT CD ON BA.ID = CD.BANK_ACCOUNT_ID ]' ||
q'[WHERE BA.ACCOUNT_NO IS NOT NULL AND CD.CHECK_NO > 0 ]' ||
q'[AND CD.STATUS != 'X' ]' ||
q'[AND CD.AMOUNT != 0 ]' ||
q'[AND ((TO_NUMBER(TO_CHAR(CD.CREATE_DATE, 'YYYYMMDDHH24MISS'))]' || IN_DATE_OPERATOR || ':1') OR ' ||
q'[(CASE WHEN CD.VOID_DATE IS NULL THEN 0 ELSE TO_NUMBER(TO_CHAR(CD.VOID_DATE, 'YYYYMMDDHH24MISS')) END]' || IN_DATE_OPERATOR || ':2')) ' ||
q'[ORDER BY BA.BRANCH_ID, BA.ACCOUNT_NO ]';
OPEN out_data
FOR l_sql_stmt
USING in_date, in_date;
END RF_SP_STFCA_PositivePay;
END RF_PKG_STFCA_PositivePay;

RoR array -count identical elements-on including value

how do we count idential values on after appending value in to array
such that
a=[]
a<<1 count of 1 is 1
a<<1 count of 1 is 2
thanks
You could do:
a.select{|v| v == 1}.size
It's only one solution
Someone will probably come up with a more specialized solution, but I would just reduce it
counts = [1,3,3].reduce({}) do |acc,n|
acc.tap do |a|
a[n] ||= 0
a[n] += 1
end
end
counts.each {|k,v| puts "#{k} was found #{v} times"}
(note that tap is ruby 1.9, and is backported in activesupport)
output of that will be
1 was found 1 times
3 was found 2 times
a = [1,2,3,4,5,1,2,2,3,4]
=> [1, 2, 3, 4, 5, 1, 2, 2, 3, 4]
a.uniq.each do |i|
?> puts i.to_s + ' has appeared ' + a.count(i).to_s + ' times'
end
1 has appeared 2 times
2 has appeared 3 times
3 has appeared 2 times
4 has appeared 2 times
5 has appeared 1 times
=> [1, 2, 3, 4, 5]

Resources