Showing posts with label Format Mask. Show all posts
Showing posts with label Format Mask. Show all posts

Tuesday, 29 November 2016

Answer with SQL: How many weekdays a year?

I'm a big fan of generating data with dual, using a perk of the connect by syntax.

I think Tom Kyte was the originator of this technique. It's not necessarily the fastest method, but it's super convenient - no table required.

Today I wanted to know how many weekdays a year, so I defined 365 rows on the fly using sysdate to turn these into each day of the year. Then I ran a simple select over this to aggregate my result
with years as (
   select to_char(trunc(sysdate,'yy')+rownum-1,'dy') dy
   from dual
   connect by level <= 365
)
select count(*)
      ,sum(case when dy in ('sat','sun') then 1 end) weekends
from years
You can see this demonstrated at livesql.oracle.com
https://livesql.oracle.com/apex/livesql/file/content_D6ZWKMK4O2IVMWGOAXIDEP61M.html
Never heard of it? I recommend you have a play. I've only dabbled myself, but if you don't have an environment to experiment with, this is free!



Thursday, 24 November 2016

Ordering & Formatting Date Columns in APEX

Quite often I'll find I'd like to display a date with the time in a column within an APEX report, but you end up wondering how to control the wrap.

This is one problem that probably has a half dozen solutions, but I think this is the cleanest. And blogging about it helps me remember next time.

Depending on your screen size, you might be faced with something that takes up too much space per row.

not a good wrap

One solution is to turn that column into a formatted character string
,to_char(created_date,'DD-MON-YYYY"<br>"HH24:MI:SS') created_date
Note the HTML break tag surrounded by double quotes, this will put the time on the next line.

Combine this with styling on the column to stop wrapping.
Column setting CSS Style: white-space:nowrap
And you'll get a neater output.

If column is varchar, won't order nice

But there's a problem. And it's a deal breaker if you want to allow the user to order the column.
Your output will be ordered Apr, Aug, Dec, Feb, Jan... sense a trend? Alphabetical, not chronological.
Applying formatting within SQL is something you generally want to avoid.

Instead, just use the funky date format mask and apply it in a declarative manner within the column attributes, along with the CSS Style. This will allow the report to honour the appropriate ordering on the date columns, whatever format mask you require.

Declarative column attributes, using DD-MON-YYYY "<br>"HH24:MI:SS

Either way you need to set "Escape special characters" to No. I think your individual date values will be safe from cross site scripting.

These settings, along with the other Column Formatting options are used frequently in my applications, particularly HTML Expression. Just remember, if you use style frequently, define a class in your page/application/theme CSS definition and use that instead.
.date_fmt {white-space:nowrap;}

#letswreckthistogether

Wednesday, 16 July 2014

Order APEX column based on hidden data

An occasional question in the forums relates to issues ordering a particular column. It's one of those things that will probably keep coming up, so it's worth having another reference out here on the web.

The basic example stems from the need to order data that might contain characters.

with data as
  (select '1'  vc from dual union all
   select '11' vc from dual union all
   select '2'  vc from dual union all
   select 'a'  vc from dual)
select vc
from data
order by vc;

VC
--
1
11
2
a

Most of the time people would want this ordered numerically as 1,2,11, then characters before or after the numerics. There are a few SQL solutions, but we need something for APEX so when you click on the column heading - it orders as you expect.

Other sample use-cases might also be found
  • in ealier versions of APEX where LOV sourced column order by return value, not display value
  • any place where data is formatted in some way
  • any occasion where you want to order data conditionally
So another example is the blob file size supplied format mask mentioned in last week's post. Here data was ordered by data values - not logically from our human perspective.
1KB
1MB
2KB

One solution offered here by Arie Geller is to prefix the column value with a hidden column
'<input type="hidden" value="'||(estimate-actual)||'" />'||abs(estimate - actual) AS variance
I found another example from Denes Kubicek back in 2008.

The solution can be even simpler & lightweight than that - use HTML comments as a prefix.

And typically we'll need to left-pad our character data to the same length - this ensures ordering compares apples to apples.

I've applied this prefix on my blob file size format mask example, to allow ordering on the column I said wouldn't order so well. The prefix is essentially the untrimmed output of filesize_mask(), with the leading spaces replaced with zeroes - and the suffix removed.

'<!--'||LPAD(dbms_lob.getlength(blob_content),10,'0')||'-->' 
||TRIM(apex_util.filesize_mask(dbms_lob.getlength(blob_content)))

Both solutions require the column to be displayed as "Standard Report Column". So if you are using text data it's best to also escape your content in the query using apex_escape.html()

Run the demo to see it in action.
Try ordering using "Size Mask" vs "Bad Order" and see where +1MB files go

The file names are scrambled using much simplified scrambling technique demonstrated here by Joe Lipman.
DBMS_RANDOM.STRING('a',length(filename))
My full SQL can be seen at the bottom of the demo page.

-- Update: Be sure to read the comments on the post regarding Patrick Wolf's elegant solution of just putting the display version of the column in the column's HTML Expression.

Wednesday, 2 October 2013

Formatting 101 - Nested single row functions

Sometimes to get the data displayed exactly how you want it, you need to employ some nested functions.

with t as (
  select null n from dual union all 
  select 0  from dual union all 
  select 0.5 from dual union all 
  select 4 from dual union all 
  select 4.5 from dual)
select to_number(n) verbatim
  ,TO_CHAR(n,'fm90.9') no_trail
  ,TO_CHAR(n,'fm90.0') trail_zero
  ,RTRIM(TO_CHAR(n,'fm90.9'),'.') trail_decimal
  ,RTRIM(TO_CHAR(NVL(n,0),'fm90.9'),'.') and_null
from t
/

  VERBATIM NO_TRAIL TRAIL_ZERO TRAIL_DECIMAL AND_NULL
---------- -------- ---------- ------------- --------
                                             0        
         0 0.       0.0        0             0        
       0.5 0.5      0.5        0.5           0.5      
         4 4.       4.0        4             4        
       4.5 4.5      4.5        4.5           4.5    

I'm curious - does anyone have formatting techniques the prefer/hate to help follow the brackets & commas?

For example, I might indent similar to JavaScript, and line up brackets/commas.
<< my_loop >>
FOR r_rec IN (
  SELECT 
    DECODE(this_value
          ,'Y', 'Yes'
          ,'N', 'No'
          ,'Maybe')
  FROM   that_table
) LOOP
  null;
END LOOP my_loop;

Scott

Wednesday, 30 May 2012

Turning maths into spelling with SQL

Awareness is fantastic.

I was aware that somehow in Oracle you could transform a number value into words. I googled a similar phrase and found a reliable location in seconds.

my sql*plus output:
SQL> column word format a10
SQL> /

    ROWNUM WORD
---------- ----------
         1 one
         2 two
         3 three
         4 four
         5 five

5 rows selected.

SQL> l
  1* select rownum, (to_char(to_date(rownum,'j'), 'jsp')) word from dual connect by level < 6
SQL>

I figure it would be a more hyperlink clickable option for displaying a small number of people. Might allow the mind to comprehend the number quicker, too. Neuroscientists?

I think it's also having important the awareness and quick access to trusted sites supporting your various hypotheses, therefore to round off this thought crumpet...

References:
I chose the AskTom result for the SQL, which I couldn't locate on the relevant documentation page.

The OTN thread I compared it to really started to nerd up on page 2/3...

Wednesday, 15 February 2012

Using format attributes in Apex


Recently I encountered some SQL in a classic Apex report that needed some attention.

To protect the innocent, let's just say the query looked like the following:
select order_id
      ,customer_id
      ,TO_CHAR((order_total/1.1)
              ,'fm$999,999,990.00') order_total 
from demo_orders;
Sure, output looks great with the currency and all, but what happens when we try to sort using the column heading?
Works great if there is the same number of digits, but as soon as we get into lower figures, our sorting appears askew.

So how should we be doing this? With attributes defined specifically for this very purpose.
So remove any formatting out of your SQL - there should be an app attribute for that.

Here endeth the simple lesson.

Scott

Friday, 17 September 2010

Trying to continue a programming meme

Do you ever find yourself thinking about something and 5 seconds later, you've arrived at a diametrically opposed thought and wonder how you got there?

I did that recently while surfing the net - I think it started when I found myself on a a site suggested by Google Reader's Explore function. It listed 5 most overused expressions on the Internet.

Sometimes I encounter internet memes that I've never heard of - maybe I'm turning into a fuddy-duddy, too esoteric in my usual surfing or just simply ignorant, I don't know; but I didn't realise "die in a fire" was such a fad. I heard it for the first time recently while watching 2 Months 2 Million, when some guy got burned in an on-line poker game and jested back with "hope you die in a grease fire". Charming.

So I googled it, as you do, to find out how much of a hit it is. Oddly, a handful of listings down I came across a programming blog.

Blogger Eric Florenzano was/is trying to start a programming meme (another word I'm almost surprised people haven't heard of).

His basic premise was to ask a simple programming question, and see how many languages the blogosphere tried to solve it with - so here's my contribution:

The Rules:
  1. Implement a program that takes in a user's name and their age, and prints hello to them once for every year that they have been alive.
  2. Post these rules, the source code for your solution, and the following list (with you included) on your blog.
  3. Bonus points if you implement it in a language not yet seen on the following list!
The List (as I found it):
  1. [Python] http://www.eflorenzano.com/blog/post/trying-start-programming-meme
  2. [Bash] http://aartemenko.com/texts/bash-meme/
  3. [C] http://dakrauth.com/media/site/text/hello.c
  4. [Java] http://adoleo.com/blog/2008/nov/25/programming-meme/
  5. [Python 3] http://mikewatkins.ca/2008/11/25/hello-meme/
  6. [Ruby] http://stroky.l.googlepages.com/gem
  7. [Ruby] http://im.camronflanders.com/archive/meme/
  8. [Lisp] http://justinlilly.com/blog/2008/nov/25/back-on-the-horse/
  9. [Lua] http://aartemenko.com/texts/lua-hello-meme/
  10. [Functional Python] http://aartemenko.com/texts/python-functional-hello-meme/
  11. [Erlang] http://surfacedepth.blogspot.com/2008/11/erics-programming-meme-in-erlang.html
  12. [Haskell] http://jasonwalsh.us/meme.html
  13. [PHP] http://fitzgeraldsteele.wordpress.com/2008/11/25/memeing-in-php-2/
  14. [Javascript] http://www.taylanpince.com/blog/posts/responding-to-a-programming-meme/
  15. [Single-File Django] http://www.pocketuniverse.ca/archive/2008/november/27/florenzano-factor/
  16. [Oracle SQL] http://triangle-circle-square.blogspot.com/2010/09/trying-to-continue-programming-meme.html
And my solution (with some added flair)

accept my_name CHAR   prompt 'name   [] '
accept age     NUMBER prompt 'age    [] '

select 'Happy '||rownum||substr(to_char(to_date('201001'||(mod(rownum,10)+20),'yyyymmdd'),'ddth'),3)
       ||' birthday, &my_name' salutation
from dual connect by level <= &age
/


SQL> @grease
name   [] Scott Wesley
age    [] 31

SALUTATION
---------------------------------
Happy 1st birthday, Scott Wesley
Happy 2nd birthday, Scott Wesley
Happy 3rd birthday, Scott Wesley
Happy 4th birthday, Scott Wesley
Happy 5th birthday, Scott Wesley
Happy 6th birthday, Scott Wesley
Happy 7th birthday, Scott Wesley
Happy 8th birthday, Scott Wesley
Happy 9th birthday, Scott Wesley
Happy 10th birthday, Scott Wesley
Happy 11st birthday, Scott Wesley
Happy 12nd birthday, Scott Wesley
Happy 13rd birthday, Scott Wesley
Happy 14th birthday, Scott Wesley
Happy 15th birthday, Scott Wesley
Happy 16th birthday, Scott Wesley
Happy 17th birthday, Scott Wesley
Happy 18th birthday, Scott Wesley
Happy 19th birthday, Scott Wesley
Happy 20th birthday, Scott Wesley
Happy 21st birthday, Scott Wesley
Happy 22nd birthday, Scott Wesley
Happy 23rd birthday, Scott Wesley
Happy 24th birthday, Scott Wesley
Happy 25th birthday, Scott Wesley
Happy 26th birthday, Scott Wesley
Happy 27th birthday, Scott Wesley
Happy 28th birthday, Scott Wesley
Happy 29th birthday, Scott Wesley
Happy 30th birthday, Scott Wesley
Happy 31st birthday, Scott Wesley

31 rows selected.


To get the format in context (st | nd | th), I had to do some manipulation with rownum. I've used the first solution I came to that worked, I'd be interested to know if anyone has any normalised solutions.

ScottWe