select minimum value from three different columns oracle - oracle

I have three tables (IDENTIFIER, LOCGRP, AFFILIATION) and they are joined by a column (id). They each have "START_DT" columns, and I want the minimum of those columns. Further, I need to select the minimum start date of the minimums for each id across the columns. The SQL I'm using to illustrate is:
SELECT id, min(min_i_start, min_lg_start, min_af_start) AS min_start
FROM (
SELECT
i.id
, min(i.START_DT) AS min_i_start
, min(lg.START_DT) AS min_lg_start
, min(af.START_DT) AS min_af_start
FROM IDENTIFIER i
INNER JOIN LOCGRP lg ON lg.id = i.id
INNER JOIN AFFILIATION af ON af.id = i.id
GROUP BY i.id
)
Of course, I knew this wouldn't work because min() is an aggregate function in Oracle, so it gives ORA-00909: invalid number of arguments. But it illustrates my objective: to get the minimum value from across three columns.
To restate: the inner subquery selects three minimum dates for each record. I would like to further select the minimum of the minimums (one value) for each record.
SQL fiddle to illustrate: http://sqlfiddle.com/#!4/9cf9d9/2
Any suggestions?

Not MIN, but LEAST:
least(min_i_start, min_lg_start, min_af_start)

Related

How to apply a filter based on the current row

I'm building a calculated column that needs to sum all the rows in the same table that share a few common properties and have a greater date value.
I know I need to use calculate to break the filter context, but I'm not sure how to reference the row being calculated vs the table of the same name inside the calculate function. In Sql, this would be done as a self join with two different aliases for the same table, what is the DAX equivalent?
SQL pseudo code:
select
t1.Name
,sum(t2.a)
from table t1
inner join table t2 on t1.b = t2.b
and t1.c < t2.c
group by t1.name
DAX (how do I correctly reference outer row vs inner table?):
calculate(sum(table[a]),
filter(all(table), table[b] = table[b])
)
As suggested by #RADO, the earlier function does this (but you might not guess that from the name!).
Using my previous example, it looks like this:
calculate(sum(table[a]),
filter(all(table), table[b] = earlier(table[b]))
)

How to add decode but also have count, group by and order by - not a group by expression

I'm rather new to Oracle. I'm trying to do a count of ports for a vendor/model. However, I only want ones with port_addr_status of 3 or 4. For some reason, I'm getting error
ORA-00979 not a group by expression
This is what I have so far. It works without the decode part, but I don't think the part with pi.port_addr.status in ('3','4') works without it. I'm open to working around that issue as well.
select
count(pi.port) as cnt, d.VENDOR, trim(d.model) as model,
decode(pi.PORT_ADDR_STATUS, '1', 'Unassigned', '2','Pending','3','In Service',
'4','Pending Disco', '5','Trouble', '6','Reserved',
'7','Reserved Capacity', pi.PORT_ADDR_STATUS)
from
table1 pi,
table2 d,
table3 c
where
pi.id = d.id and
pi.circuit_id = c.circuit_id
and pi.port_addr_status in ('3','4')
and (d.dslam_type_desc not in ('AGGREGATOR') or d.dslam_type_desc is null)
and d.DSLAM not like '%#%'
group by
d.VENDOR, d.model --, trim(d.model), pi.RACK, pi.SHELF, pi.SLOT, pi.PORT, pi.BROADBAND_CIRCUIT_ID, d.DSLAM,
order by
d.VENDOR asc, cnt desc
This is sample output:
1031 Adtran TA5000
10 Adtran TA1248V
3 Adtran TA1248
Since the decoded port type is not required in your output, just remove it from the select list. Group By should include everything in the select list except the aggregate functions. The below query should do the job:
select
count(pi.port) as cnt, d.VENDOR, trim(d.model) as model
from
table1 pi,
table2 d,
table3 c
where
pi.id = d.id and
pi.circuit_id = c.circuit_id
and pi.port_addr_status in ('3','4')
and (d.dslam_type_desc not in ('AGGREGATOR') or d.dslam_type_desc is null)
and d.DSLAM not like '%#%'
group by
d.VENDOR, trim(d.model)
order by
d.VENDOR asc, cnt desc
Note that the filter down to specific port types is achieved here:
and pi.port_addr_status in ('3','4')
in the where clause - the decode statement in your original query did nothing to solve your requirements and was the direct cause of the error. In a basic aggregate query like this, group by should have every item that is in the select list that is not an aggregate function.
You might use decode statement in the select list with an aggregation function preferably max as
max( decode(pi.PORT_ADDR_STATUS, '1', 'Unassigned', '2','Pending', .... )
The reason you're getting that error is:
when using a GROUP BY clause you are asking the DBMS to give you a single row corresponding to your GROUP BY list
in your case, you are asking for one row per (Vendor, Model) combination
since each of these rows represents possibly many "underlying" rows (say, e.g. 5 rows for Vendor=A and Model=B), the only other fields you can have in the select list must be aggregates (that's why the "count" field works, it counts the rows, i.e. it can take many row values and return a single value)
the DECODE function is not an aggregate function - it can't "collapse" multiple values into one value (like, say, MAX() can)
It looks to me as if your DECODE function returns strings, so I recommend you aggregate the strings with the LISTAGG function (so if your 5 rows have values of 'asdf', 'fdsa', 'qwer', 'rewq', and 'zxcv' the LISTAGG function would return a single string: 'asdf,fdsa,qwer,rewq,zxcv')
So you would replace your DECODE(...) call with, e.g. LISTAGG(DECODE(...), ',')
Reference for LISTAGG function: https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions089.htm#SQLRF30030

Joins are not giving the right answers

1)select count(*) from LCL_RKM_AuditForm; **O/P : 868**
2)select count(*) from RKM_KnowledgeArticleManager; **O/P : 8511**
3)select count(*) from
LCL_RKM_AuditForm A
**right** outer join
RKM_KnowledgeArticleManager B
on A.ARTICLE_ID=B.DocID; **O/P : 9216**
4)select count(*) from
LCL_RKM_AuditForm A
**left** outer join
RKM_KnowledgeArticleManager B
on A.ARTICLE_ID=B.DocID; **O/P : 1973**
5)select count(*) from
LCL_RKM_AuditForm A,RKM_KnowledgeArticleManager B
**where** A.ARTICLE_ID=B.DocID; **O/P : 1973**
My understanding is that.,.
Left outer join will Displays all the values in A table and common values in B table.
Right outer join will Displays all the values in B table and common values in A table.
What does that Common Values refers to ? If its the left outer join which means it should give only 868 results right ? And if its right outer join which means it should give only 8511 results right ?
5th statement i have used WHERE clause which means it should give me only 868 entries right ?
Please help me on this.
Your expected results appear to be based on the false assumption that there is a one-to-one mapping between rows in the two tables.
For a standard inner join (as in your last query), every matching combination of rows from the two tables is returned. Since you are getting more results than there are rows in the first table, it must be true that a given row in the first table may have multiple matching rows in the second table.
For instance, if there is one row in table A with ArticleID = 1, and two rows in Table B with DocID = 1, then a join of the two tables on these fields will produce 2 rows.
When you change to an outer join, you will get at least the same number of rows as the inner join, and potentially more. An outer join will return the same rows as the corresponding inner join; plus, for any row in the "inner" table that does not have any match in the "outer" table, it will return that one row, with NULL values for columns from the second table.
Your LEFT OUTER JOIN returns the same number of rows as the inner join; this implies that every row in table A has at least one matching row in table B.
Your RIGHT OUTER JOIN returns many more rows. This implies that there are many rows in table B that have no matching row in table A.

Vertica subquery with limit

I found problem in writing subquery with limit 1 to get the top record.
Here is my problem example.
Table Master(id,set)
Table Detail(id,set,code)
i am trying to get the latest code for each set in Master table.
Following is the query which i tried but got an error that limit 1 is not supported for correlated subqueries and it should contain GROUP By clause.
select id,set,(select code from detail where set=master.set order by id desc limit 1) from master;
And the result wolud be like
please help me if this is wrong way, i am new to this vertica database.
thnk you.
I'm not sure about that particular error, but you can use the rank() analytic function to produce results like this:
select id, set, code from (
select M.id, D.set, D.code, rank() over (partition by D.set order by D.id desc) as rank
from detail as D
right outer join master as M
on D.set = M.set) as ranks
where rank = 1
order by id;
The inner subquery uses the rank() function to assign a rank to each row within a set. The outer query just picks out rows with rank 1.

Why is "group by" giving only one column as output?

I have a table something like this:
ID|Value
01|1
02|4
03|12
01|5
02|14
03|22
01|9
02|32
02|62
01|13
03|92
I want to know how much progress have each id made (from initial or minimal value)
so in sybase I can type:
select ID, (value-min(value)) from table group by id;
ID|Value
01|0
01|4
01|8
01|12
02|0
02|10
02|28
02|58
03|0
03|10
03|80
But monetdb does not support this (I am not sure may be cz it uses SQL'99).
Group by only gives one column or may be average of other values but not the desired result.
Are there any alternative to group by in monetdb?
You can achieve this with a self join. The idea is that you build a subselect that gives you the minimum value for each id, and then join that to the original table by id.
SELECT a.id, a.value-b.min_value
FROM "table" a INNER JOIN
(SELECT id, MIN(value) AS min_value FROM "table" GROUP BY id) AS b
ON a.id = b.id;

Resources