I want the output of my SQL to leave a blank line when any of three columns (a b or c below) change.
So if the table had columns a b c and d, you end up with a report like this:
a b c d #<- column names
-------
1 a a a #<- V - data itself
1 a a b
#<- level break here because 1 a b is different from 1 a a
1 a b c
From Googling, I have seen BREAK might solve this.
But from what I can make out this pertains to one column.
I then thought what if I have a computed column.
a is numeric, b & c are alphanumeric data types.. so I guess I could possibly use CONCAT plus TO_CHAR..
I am wondering if anyone can give me some pointers?
Cheers.
You can break on more than one column:
SQL> break on a skip 1 duplicates on b skip 1 duplicates on c skip 1 duplicates
SQL> select * from your_table
A B C D
---------- - - -
1 a a a
1 a a b
1 a b c
3 rows selected.
If you issue a plain break it shows what is set:
SQL > break
break on a skip 1 dup
on b skip 1 dup
on c skip 1 dup
Another option is to generate an extra column expression of your composite key, break on that, and set it not to display:
SQL> break on composite skip 1
SQ>> column composite noprint
SQL> select t.*, a||':'||b||':'||c as composite from your_table t;
A B C D
---------- - - -
1 a a a
1 a a b
1 a b c
3 rows selected.
which has the advantage of not showing multiple blank lines if more than one column changes at the same time.
I've separated the values with a colon; the idea of that is to use a character that doesn't appear in the values themselves, to avoid an accidental clash. If any of the columns could actually have a colon then pick something else more obscure.
Related
Consider the following table:
A | B | C
+++++++++++++++++++
15 | | 25
10 | 20 | 30
which, for the sake of simplicity, contains only two rows. Now, when I issue this query
SELECT A, B, C FROM whatever
I would like to obtain only the second row, i. e. only these rows, where every value is non-null / not empty. Instead, I get both rows.
Is there a better way than doing the following? :
SELECT A, B, C FROM whatever
WHERE A != '' AND B != '' AND C !=''
You can use function empty to mark empty or non-empty rows as 1 if the row is empty and 0 if there is any data in it.
So your code will look like this
SELECT A
, B
, C
, empty(A) as empty_A
, empty(B) as empty_B
, empty(A) as empty_C
FROM whatever
WHERE empty_A = 0 AND empty_B = 0 AND C empty_C = 0
Thus, if there is at least one empty in columns A / B / C, then these rows will not fall into selection
In addition to the previous answer, just to be more straight, you can use the following code that combine the empty function with the trim one to spot also columns containing one or more white spaces.
SELECT col_1, col_2, col_3
FROM my_table
WHERE empty(trim(col_2)) = 0
I have to deal with a little problem in Oracle...I have a table with 2 columns, the first column contains dates, the second one contains imports. The "import column" could have both NULL or not NULL values.
What I want to do is to order by the date column (and this is easy :) ) and then split the table in blocks of contiguous NULL or not NULL values in the "import column" adding a third column which numbers the blocks.
Example:
Date Import
01/01/2017 99.12
01/02/2017 18.19
01/03/2017 22.92
01/04/2017 28.10
01/05/2017
01/06/2017
01/07/2017
01/08/2017 33.78
01/09/2017 20.30
01/10/2017 12.33
01/11/2017
01/12/2017 1.68
this table should became
Date Import Block
01/01/2017 99.12 1
01/02/2017 18.19 1
01/03/2017 22.92 1
01/04/2017 28.10 1
01/05/2017 2
01/06/2017 2
01/07/2017 2
01/08/2017 33.78 3
01/09/2017 20.30 3
01/10/2017 12.33 3
01/11/2017 4
01/12/2017 1.68 5
You can use analytic functions like this:
select d, import, sum(state_change) over (order by d) as block
from
(
select d, import, import_state,
case when import_state = lag(import_state) over (order by d, import)
then 0 else 1 end state_change
from
(
select d, import, case when import is not null then 1 else 0 end as import_state
from t
)
);
(NB I renamed your DATE column to D as DATE is a reserved word).
Breaking it down, starting with the innermost query:
select d, import, case when import is not null then 1 else 0 end as import_state
from t
This adds a column import_state that is 1 when import is not null, 0 if it is null. This creates "blocks" but they are numbered 1,0,1,0,... instead of 1,2,3,4,...
The next part compares each import_state with that on the preceding row, to check for changes. Column state_change is 1 when there has been a change, 0 otherwise - so now the first row for each "block" has a 1 and the reset have a 0.
The outer part then simply sums the state_change values cumulatively to give the required result.
There may well be a simpler solution!
I have the following situation:
column 1 column 2 column 3
A 1 1
A 1 2
B 3 4
B 3 5
I need to color my letters when the value in column 2 never occurs in column 3. But I need to color all my letters. Does anyone know how to write a case statement for this?
So I'll explain my example: I dont't need to color the letter A because there is a match between column 2 and 3 and the first row.
I do need to color my B's because there is never a match between columns 2 and 3.
I already tried this:
count(distinct(case when "Column 2" != "Column 3" then 1 else 0 end))
but this gives a result for each row and I need a result for the total package.
Thanks!
You can approach this as following:
Create a logical column on your analysis that does a case statement that returns 1 or 0 depending if the values of column2 and column3 are the same (pretty much like the case-when that you provided on your answer but without the count distinct).
Wrap that case statement with a MAX grouped by your column1. This will give you either a consistent 1 or 0 across all your different values of column1. You can use this value for your conditional formatting. The key here is to use the aggregated function with the group by.
You have here some oracle documentation on how to use the logical SQL group by.
Hope that helps! Good luck!
This question already has answers here:
Why does Oracle return specific sequence if 'orderby' values are identical?
(4 answers)
Closed 7 years ago.
All, Let's say the SQL looks like below.
Select a, b ,c from table1 order by c
If all the rows in table1 have the same field value in the field c. I want to know if the result has the same order for each time I executed the SQL.
Let's say data in the table1 looks like below.
a b c
-------------------------------------------
1 x1 2014-4-1
....
100 x100 2014-4-1
....
1000 x1000 2014-4-1
....
How Oracle determine the rows sequence for the same order by value?
Added
Will they be random sequence for each time?
One simple answer is NO. There is no guarantee that the ORDER BY on equal values will return the same sorted result every time. It might seem to you it is always stable, however, there are many reasons when it could change.
For example, the sorting on equal values might defer after:
Gathering statistics
Adding an index on the column
For example,
Let's say I have a table t:
SQL> SELECT * FROM t ORDER BY b;
A B
---------- ----------
1 1
2 1
3 2
4 2
5 3
6 3
6 rows selected.
The sorting on the column having similar values is just like:
SQL> CREATE TABLE t1 AS SELECT * FROM t ORDER BY b, DBMS_RANDOM.VALUE;
Table created.
SQL> SELECT * FROM t1 ORDER BY b;
A B
---------- ----------
1 1
2 1
4 2
3 2
5 3
6 3
6 rows selected.
So, similar data in bot the tables, however, ORDER BY on the column having equal values, dos not guarantee the same sorting.
They must not be random (change each time), but the order is not guaranteed (change sometimes).
I'm tring to use hive to analysis our log, and I have a question.
Assume we have some data like this:
A 1
A 1
A 1
B 1
C 1
B 1
How can I make it like this in hive table(order is not important, I just want to merge them) ?
A 1
B 1
C 1
without pre-process it with awk/sed or something like that?
Thanks!
Step 1: Create a Hive table for input data set .
create table if not exists table1 (fld1 string, fld2 string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
(i assumed field seprator is \t, you can replace it with actual separator)
Step 2 : Run below to get the merge data you are looking for
create table table2 as select fld1,fld2 from table1 group by fld1,fld2 ;
I tried this for below input set
hive (default)> select * from table1;
OK
A 1
A 1
A 1
B 1
C 1
B 1
create table table4 as select fld1,fld2 from table1 group by fld1,fld2 ;
hive (default)> select * from table4;
OK
A 1
B 1
C 1
You can use external table as well , but for simplicity I have used managed table here.
One idea.. you could create a table around the first file (called 'oldtable').
Then run something like this....
create table newtable select field1, max(field) from oldtable group by field1;
Not sure I have the syntax right, but the idea is to get unique values of the first field, and only one of the second. Make sense?
For merging the data, we can also use "UNION ALL" , it can also merge two different types of datatypes.
insert overwrite into table test1
(select x.* from t1 x )
UNION ALL
(select y.* from t2 y);
here we are merging two tables data (t1 and t2) into one single table test1.
There's no way to pre-process the data while it's being loaded without using an external program. You could use a view if you'd like to keep the original data intact.
hive> SELECT * FROM table1;
OK
A 1
A 1
A 1
B 1
C 1
B 1
B 2 # Added to show it will group correctly with different values
hive> CREATE VIEW table2 (fld1, fld2) AS SELECT fld1, fld2 FROM table1 GROUP BY fld1, fld2;
hive> SELECT * FROM table2;
OK
A 1
B 1
B 2
C 1