How to leave out empty values in queries? - sqlplus

I'm trying to place these values into one column, but sometimes there is no value for 'County'. How can I make it that It doesn't show up as Name_of_town, , Postcode?
SQL> select SuppName || ', ' || Street || ', ' || Town || ', ' || County || ', ' || PostCode AS "Supplier Address"
2 from Suppliers
3 ORDER BY 1;
This is what I currently get back from the query. (Example of ',' by itself is on the first query result)
Supplier Address
--------------------------------------------------------------------------------
Business Systems Ltd., 155 Stradleigh Place, London, , E10 6LL
Fastorder Stationers, Riverside View, Newport, Gwent, NP1 7XJ
I.T. Supplies (Wales), 3 Marlborough Ave., Cardiff, , CF1 1IT
Legal Services Ltd., Westway Road, London, , N8 8PA
Office Matters, 20 Berrick Street, Bridgend, Mid Glam., CF38 3BB
TKG Tools Ltd., 7 High Street, Swansea, , SA7 2WG

It seems like Oracle's NVL is the way to go. It will replavce null values with a string of your choosing. I am assuming when you say there is no value for County, that field contains null. Otherwice oracle REPLACE would work.
NVL
Try this:
select SuppName || ', ' || Street || ', ' || Town || ', ' || NVL(County, 'No_County') || ', ' || PostCode AS "Supplier Address"
from Suppliers
ORDER BY 1;

Related

Exact Online import GLTransactions with automatic reconciliation

I am using our query tool to generate XML files for the topic GLTransactions of the XML API of Exact Online. The input for these files are XML Audit Files coming from Twinfield (XAF 3.1 format).
Since Exact Online has a mixed ledger and lots of constraints, it is not possible to directly load the bank entries. Instead, the bank transactions are posted into a separate General Ledger account of Exact Online with a separate journal as a first step when loading the XML Audit Files from Twinfield.
In the next step, the contents in Exact Online of the reserved General Ledger account are posted in the banking journal. Exact Online itself generates the other half as associated transaction lines for the banking general ledger.
The query used to generate the bank entries is:
create or replace table bank#inmemorystorage
as
select case
when substr(tle.description, 1, instr(tle.description, '/') - 1) = 'BNK'
then '20'
when substr(tle.description, 1, instr(tle.description, '/') - 1) = 'BNK2'
then '21'
else '??'
end
txn_journalcode
, txn.financialyear txn_financialyear
, txn.financialperiod txn_financialperiod
, txn.entrynumber txn_entrynumber
, txn.date txn_date
, tle.date tle_date
, tle.linenumber tle_linenumber
, substr(tle.description, instr(tle.description, '/') + 1, instr(tle.description, ':') - instr(tle.description, '/') - 1) tle_glaccountcode_target
, substr(tle.description, instr(tle.description, ':') + 2) tle_description
, trim(tle.accountcode) tle_accountcode
, tle.glaccountcode glaccountcode_source
, tle.amountdc tle_amountdc
, tle.vatcode tle_vatcode
, tle.yourref tle_yourref
from exactonlinerest..transactionlines tle
join exactonlinerest..transactions txn
on tle.entryid = txn.entryid
where tle.glaccountcode like '290%'
and substr(tle.description, instr(tle.description, '/') + 1, instr(tle.description, ':') - instr(tle.description, '/') - 1) not like '11%' /* Not a bank account. */
order
by tle.entrynumber
, tle.linenumber
select 'GLTransactions\99-Interim-empty.xml'
filename
, stg.fileprefix
|| chr(13)
|| '<GLTransactions>'
|| xml
|| chr(13)
|| '</GLTransactions>'
|| stg.filepostfix
filecontents
from ( select listagg
( chr(13)
|| '<GLTransaction entry="'
|| txn_entrynumber
|| '">'
|| chr(13)
|| '<Journal code="'
|| txn_journalcode
|| '" />'
|| chr(13)
|| '<Date>'
|| substr(xmlencode(txn_date), 1, 10)
|| '</Date>'
|| chr(13)
|| xml
|| chr(13)
|| '</GLTransaction>'
, ''
) xml
from ( select txn_date
, txn_journalcode
, txn_financialyear
, txn_financialperiod
, txn_entrynumber
, listagg
( chr(13)
|| '<GLTransactionLine type="40" linetype="0" line="'
|| tle_linenumber
|| '" offsetline="1" status="20">'
|| chr(13)
|| '<Date>'
|| substr(xmlencode(tle_date), 1, 10)
|| '</Date>'
|| chr(13)
|| '<FinYear number="'
|| txn_financialyear
|| '" />'
|| chr(13)
|| '<FinPeriod number="'
|| txn_financialperiod
|| '" />'
|| chr(13)
|| '<GLAccount code="'
|| case
when tle_glaccountcode_target = '1560'
then '2902' /* Separate interim GL account, Twinfield does not provide separated. */
else xmlencode(tle_glaccountcode_target)
end
|| '" />'
|| case
when tle_description is not null
then chr(13)
|| '<Description>'
|| xmlencode(tle_description)
|| '</Description>'
end
|| case
when tle_accountcode is not null
then chr(13)
|| '<Account code="'
|| xmlencode(tle_accountcode)
|| '" />'
end
|| chr(13)
|| '<Amount>'
|| '<Currency code="EUR" />'
|| '<Value>'
|| -1 * tle_amountdc
|| '</Value>'
|| case
when tle_glaccountcode_target like '4%'
then '<VAT code="GB" />' /* GB = No VAT. */
else ''
end
|| '</Amount>'
|| chr(13)
|| '</GLTransactionLine>'
, ''
)
xml
from bank#inmemorystorage
group
by txn_date
, txn_journalcode
, txn_financialyear
, txn_financialperiod
, txn_entrynumber
)
)
join settings#inmemorystorage stg
on 1=1
In the column tle_yourref in bank#inmemorystorage there is a comma-separated list of associated sales/purchase invoices.
When manually entering the General Ledger transaction on the bank journal, the contents of your ref are populated by the reconciliation window. However, when I export the XML file from Exact Online with transactions, the your ref is missing.
At this moment I seem uncapable to automatically reconcile through an XML or REST API of Exact Online these transactions in the bank journal.
As a workaround you can select each individual account in Reconciliation window (they practically all amount to EUR 0) and then choose Automatic reconciliation. But there are too many accounts to do it with each conversion from Twinfield to Exact Online.
Is there an alternative way to associate invoices with the bank transactions through an API (REST or XML) of Exact Online?
If there is a 1 on 1 relation between the invoice and the payment (so only 1 invoice and 1 payment) you can use <References><InvoiceNumber>put invoice entrynumber here</InvoiceNumber></References> in the bank entry to have it automatically reconciled.
Another possibility is to create an XML file with the topic MatchSets (see documentation) to have it matched afterwards.
Additionally, you can also say:
<References><EntryNumber>10000012</EntryNumber><InvoiceNumber>FAC0001</InvoiceNumber></References>
This always works when the relation is 1=1.
If you specify only the invoice number the matching often fails silently.

Using dynamic table name in db2

Currently in my project development need of generating the record count based on certain criteria where the table names are stored in separate table.For instance say xx table stores the table name under the column name is tableInfo.
I've written the stored procedure in such a way that
DECLARE FGCURSOR CURSOR FOR SELECT tableInfo FROM xx WHERE col1='PO';
OPEN FGCURSOR;
FETCH FROM FGCURSOR INTO FILEGROUPMEM;
WHILE SQLCODE <> 100
DO
SET COUNTVal = 'SELECT COUNT(*) FROM ' || FILEGROUPMEM || ' WHERE ICLS= ' || CLASS || ' AND IVEN= ' || VENDOR || ' AND ISTY= ' || STYLE || ' AND ICLR= ' || COLOR || ' AND ISIZ= ' || SIZE ;
IF(COUNTVal >= 1) THEN
RETURN 1;
END IF;
FETCH FROM FGCURSOR INTO FILEGROUPMEM;
END WHILE;
CLOSE FGCURSOR;
Getting the exception on executing the procedure saying that
Message: [SQL0420] Character in CAST argument not valid. Cause . . . .
. : A character in the argument for the CAST function was not
correct. Recovery . . . : Change the result data type to one that
recognizes the characters in the CAST argument, or change the argument
to contain a valid representation of a value for the result data type.
Try the request again.
This line is not correct:
SET COUNTVal = 'SELECT COUNT(*) FROM ' || FILEGROUPMEM || ' WHERE ICLS= ' || CLASS || ' AND IVEN= ' || VENDOR || ' AND ISTY= ' || STYLE || ' AND ICLR= ' || COLOR || ' AND ISIZ= ' || SIZE ;
To use it the way you are trying, you'd have to use a static SQL statement like so
exec sql SELECT COUNT(*) INTO :COUNTVal
FROM MYTBL
WHERE ICLS= :CLASS AND IVEN= :VENDOR AND ISTY= :STYLE
AND ICLR= :COLOR AND ISIZ= :SIZE;
However, while a static statement can use variables, the table name in the FROM clause can not be variable.
Thus you have to prepare and use a dynamic statement. Unfortunately, SELECT INTO can not be used in a dynamic statement. VALUES INTO can be used dynamically.
set wSqlStmt = 'VALUES ( SELECT COUNT(*) FROM ' || FILEGROUPMEM
|| ' WHERE ICLS= ' || CLASS || ' AND IVEN= '
|| VENDOR || ' AND ISTY= ' || STYLE || ' AND ICLR= '
|| COLOR || ' AND ISIZ= ' || SIZE ||') INTO ?';
exec sql PREPARE S1 FROM :wSqlStmt;
exec sql EXECUTE S1 USING COUNTVal;
WARNING the above code could be subject to SQL Injection attacks. To protect against SQL injection, dynamic SQL should use parameter markers instead of concatenating input directly to a statement. While you can't use a parameter marker for the table name, you can for the rest of the variables like so:
set wSqlStmt = 'VALUES ( SELECT COUNT(*) FROM ' || FILEGROUPMEM
|| ' WHERE ICLS= ? AND IVEN= ? '
|| ' AND ISTY= ? AND ICLR= ?'
|| ' AND ISIZ= ?) INTO ?';
exec SQL PREPARE S1 FROM :wSqlStmt;
exec SQL EXECUTE S1 USING :CLASS, :VENDOR, :STYLE, :COLOR, :SIZE, :COUNTVal;

Oracle Stored Procedure update rows if records exist

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;

How can I do this query in Grails?

I have two domain classes:
class User {
String nickname
}
and
class Episodes {
String name
User sentBy
}
I want to make a Ranking about who has sent more episodes.
So I did this query, and gives me the result that I want.
SELECT user.nickname, count(episodes.id) total
FROM user
JOIN episodes on user.id = episodes.sent_by
GROUP BY user.nickname
ORDER BY total DESC
What's the best way to run this query in my Controller? How?
I would use HQL for this:
def results = User.executeQuery(
'SELECT e.sentBy.nickname, count(e) as total ' +
'FROM Episodes e ' +
'GROUP BY e.sentBy.nickname ' +
'ORDER BY total desc')
The result will be a list of Object[] arrays, with the 1st element being the nickname and the 2nd being the count, e.g.
for (Object[] row in results) {
println "User ${row[0]} has ${row[1]} episodes"
}
There is an answered question about your concern:
Using groupProperty and countDistinct in Grails Criteria

PostgreSQL precendence when querying with ILIKE

Two fixtures:
one:
firstname: John
lastname: Doe
user_id: 1
two:
firstname: Jane
lastname: Doe
user_id: 1
In my unit test, I have the following:
test "Searching for a contact gets the right person" do
search = Contact.search("John")
assert_equal 1, search.count
search = Contact.search("Doe")
assert_equal 2, search.count
search = Contact.search("John Doe")
assert_equal 1, search.count
search = Contact.search("John ")
assert_equal 1, search.count
search = Contact.search("Doe John")
assert_equal 1, search.count
end
...and finally my model, which calls the search method looks like:
def self.search(search)
# Check if the search query has more than one word
search_split = search.split(" ")
if search_split.count > 1
# User must be searching for a first and last name
first_word = '%' + search_split[0] + '%'
second_word = '%' + search_split[1] + '%'
conditions = "
firstname ILIKE ? OR lastname ILIKE ?
AND
firstname ILIKE ? OR lastname ILIKE ?",
first_word, first_word, second_word, second_word
where(conditions)
else
# Just searching for a first OR last name
# Strip any whitespace
str = search_split[0]
query = '%' + str + '%'
conditions = "firstname ILIKE ? OR lastname ILIKE ?", query, query
where(conditions)
end
end
All tests pass except the one that does a test for "John Doe". It actually ends up pulling "Jane Doe" as well.
I'm thinking there is some kind of precedence issue with calling the two OR's before the adjoining AND, but does it make sense of what I'm trying to accomplish?
I'm not at the point where I'm refactoring just yet; just trying to get to green so I can move forward. Thanks for any help in advance!
You need a bit of reorganization to get the logic you're after:
conditions = "
(firstname ILIKE ? AND lastname ILIKE ?)
OR
(firstname ILIKE ? AND lastname ILIKE ?)",
first_word, second_word, second_word, first_word
That should match both "John Doe" and "Doe John" but not "Jane Doe" when you call:
Contact.search('Jo Do')
You don't actually need the parentheses because AND has a higher precedence than OR in Boolean Algebra (and SQL's logic is based on Boolean Algebra) but there's no good reason not to include them.

Resources