CONCATE UNIQUE VALUES BASED ON ID IN INFORMAITCA - oracle

SCENARO/input,
COL1 COL2
100 ABC
101 PQR
100 ABC
100 OPQ
101 HDR
101 PQR
Expected OUTPUT:
COL1 COL2
100 ABC,OPQ
101 PQR,HDR

This is one of classic string aggregation issue. Pls follow below steps.
using SRT order the data and get distinct. So, click enable distinct and then make sure you are ordering col1 first.
using expression transformation concat the COL2. Create 5 ports - in_out means input+output, in_ means input only, v_ means variable port and so on.
in_out_col1
in_col2
v_col2 = iif( in_out_col1=v_prev_col1, v_col2||',' ||in_col2,in_col2)
v_prev_col1 = in_out_col1
out_col2=v_col2
Create an AGG, group by col1. Create a new column max_col2 and assign the max value to it.
in_out_col1
in_col2
out_max_col2= MAX(in_col2)
Connect in_out_col1 to col1 and out_max_col2 to col2 for your desired data.

Related

Google Sheets query order by row ends with

I have table of data which looks like:
J2150 IMPAC-BRIGA (RH)
J2283 BAYWA-FERGU (NK)
J2284 BAYWA-DIAPR (NK)
J2320 BOSCH-OWNER (ML)
J2475 GIPPS-GIPWF (NK)
J2568 GWFLD-CASTL-002 (PW)
J2663 AUSTRA-BARHA-001 (NK)
J2690 PHOTO-NEWAT (KT)
J2692 TETRI-MANGA (NK)
I'm using a Google Sheets query but I want to order the table by the project manager ie the initials at the end eg (CM).
I've been trying to use 'ends with' and 'order by' but this doesn't do what I want; eg
select Col2 where Col2 ends with '(CM)' group by Col2 order by Col2
I could separate out the initials into a new column in the original data, select and sort on that but is there an elegant way of sorting by the end of the row rather than the start?
try the below formula:
Assuming your data range is A2:B, if not then change your data range accordingly
=Query({A2:A,B2:B,Arrayformula(SPLIT(B2:B," "))},"Select Col1,Col2 where Col4 <>'' order by Col4")
=ArrayFormula(QUERY(REGEXEXTRACT(A:A,"^(.+?) (.+)$"),"select * where Col2 ends with '(NK)' order by Col2"))
I realised my original question wasn't precise enough: the rows are one record and not separate entries
J2150 IMPAC-BRIGA (RH)
J2283 BAYWA-FERGU (NK)
J2284 BAYWA-DIAPR (NK)
J2320 BOSCH-OWNER (ML)
J2475 GIPPS-GIPWF (NK)
J2568 GWFLD-CASTL-002 (PW)
J2663 AUSTRA-BARHA-001 (NK)
J2690 PHOTO-NEWAT (KT)
J2692 TETRI-MANGA (NK)
But I did want to sort on the two-letter suffix in the () at the end.
This is what I came up with:
query({'Project Overview'!$B$1:$B$373,
arrayformula(REGEXEXTRACT('Project Overview'!$B$1:$B$373,"\(([A-Z]{2})\)")),
'Project Overview'!$c$1:$d$373},
"select Col1, Col2, Col3, Col4 where Col3 is not null order by Col2
label Col1 'Project', Col2 'Project Manager'", 1)
This extracts the first column, 'B' and then uses REGEXTRACT to pull the 2-letter code from the same data as the second column.
Project
Project Manager
4-Oct-21
11-Oct-21
Kinley (CM)
CM
1
Kinley (CM)
CM
1
J1911 KINEL-KENT (CM)
CM
4
8
J2741 SIGNL-DARLP (DD)
DD
2
J2745 MANGO-FEASB (DD)
DD
1
J2754 CPENG-WANG (DD)
DD
16
8
J2754 CPENG-WANG (DD)
DD
20
16
J2754 CPENG-WANG (DD)
DD
4
DARETON O&M (JM)
JM
0.5
0.5
DARETON O&M (JM)
JM
2
4

Allow multiple values from SSRS in oracle

I have a query that gets contract_types 1 to 10. This query is being used in an SSRS report to filter out a larger dataset. I am using -1 for nulls and -2 for all.
I would like to know how we would allow multiple values - does oracle concatenate the inputs together so '1,2,3' would be passed in? Say we get select -1,0,1 in SSRS, how could we alter the bottom query to return values?
My query to get ContractTypes:
SELECT
ContractType,
CASE WHEN ContractType = -2 THEN 'All'
WHEN ContractType = -1 THEN'Null'
ELSE to_Char(ContractType)
END AS DisplayFigure
FROM ContractTypes
which returns
ContractType DisplayFig
-1 Null
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
This currently is only returning single values or all, not muliple values:
SELECT *
FROM Employee
WHERE NVL(CONTRACT_TYPE, -1) = :contract_type or :contract_type = -2
I'm assuming we want to do something like:
WHERE NVL(CONTRACT_TYPE, -1) IN (:contract_type)
But this doesn't seem to work.
Data in Employee
Name ContractType
Bob 1
Sue 0
Bill Null
Joe 2
In my report, I want to be able to select contract_type as -1(null),0,1 using the 'allow muliple values' checkbox. At the moment, I can only select either 'all' using my -2 value, or single contract types.
My input would be: contract type = -1,1,2
My output would be Bill, Bob, Joe.
This is how I'm executing my code
I use SSRS with Oracle a lot so I see where you're coming from. Thankfully, they work pretty well together.
First make sure the parameter is set to allow multiple values. This adds a Select All option to your dropdown so you don't have to worry about adding a special case for "All". You'll want to make sure the dataset for the parameter has a row with -1 as the Value and a friendly description for the Label.
Next, the WHERE clause would be just as you mentioned:
WHERE NVL(CONTRACT_TYPE, -1) IN (:contract_type)
SSRS automatically populates the values. There is no XML or string manipulation needed. Keep in mind that this will not work with single-value parameters.
If for some reason this still doesn't work as expected in your environment, there is another workaround you can use which is more universal and works even with ODBC connections.
In the dataset parameter properties, use an expression like this to concatenate the values into a single, comma-separated string:
="," + Join(Parameters!Parameter.Value, ",") + ","
Then use an expression like this in your WHERE clause:
where :parameter like '%,' + Column + ',%'
Obviously, this is less efficient because it most likely won't be using an index, but it works.
I don't know SSRS, but - if I understood you correctly, you'll have to split that comma-separated values list into rows. Something like in this example:
SQL> select *
2 from dept
3 where deptno in (select regexp_substr('&&contract_type', '[^,]+', 1, level)
4 from dual
5 connect by level <= regexp_count('&&contract_type', ',') + 1
6 );
Enter value for contract_type: 10,20,40
DEPTNO DNAME LOC
---------- -------------------- --------------------
20 RESEARCH DALLAS
10 ACCOUNTING NEW YORK
40 OPERATIONS BOSTON
SQL>
Applied to your code:
select *
from employee
where nvl(contract_type, -1) in (select regexp_substr(:contract_type, '[^,]+', 1, level)
from dual
connect by level <= regexp_substr(:contract_type, ',') + 1
)
If you have the comma separated list of numbers and then if you like to split it then, the below seems simple and easy to maintain.
select to_number(column_value) from xmltable(:val);
Inputs: 1,2,3,4
Output:
I guess I understood your problem. If I am correct the below should solve your problem:
with inputs(Name, ContractType) as
(
select 'Bob', 1 from dual union all
select 'Sue', 0 from dual union all
select 'Bill', Null from dual union all
select 'Joe', 2 from dual
)
select *
from inputs
where decode(:ContractType,'-2',-2,nvl(ContractType,-1)) in (select to_number(column_value) from xmltable(:ContractType))
Inputs: -1,1,2
Output:
Inputs: -2
Output:

retrieve only unique values via query

Here's the formula I currently use:
=query(IMPORTRANGE("XXXX","XXXXX!A:H"),
"select Col1,Col2,Col3,Col4,Col5,Col6,Col7,Col8
where Col1> date '"&TEXT(F1,"yyyy-mm-dd")&"' and Col3 = '"&B1&"' and Col4 = '"&D1&"'
order by Col1 desc",1)
The formula is working.
Col1 includes input dates. I retrieve only values that are after a date listed in F1.
Col3 and Col3 include some properties which are selected in cells B1 and D1, accordingly.
Col5 includes strings (client names). client name can repeat on several rows.
I'd like to retrieve just the most recent one. Any ideas on how to do it?
And, to add more fun into the question, would it be the same idea to retrieve the oldest row per client?
Here's a link to demo sheet, details in the "unique query" tab.
Another challenge can be to retrieve X number of row per client, and not just the most recent one.
try:
=SORTN(QUERY(IMPORTRANGE("1LoHg53hzQvYtOLTcDwxLY8OrKVN4F7usX8YI41BtdWg", "Activity list!A:E"),
"where Col1 > date '"&TEXT(I2, "yyyy-mm-dd")&"'
and Col2 = '"&I3&"'
order by Col1 desc", 1), 99^99, 2, 4, 1)
SORTN explained:
99^99 all rows - no limits
2 means "merge mode"
4 collapse 4th column into unique values
1 return 4th column ascending - 0 for descending
Solution
I am basing myself on a SQL expression that would achieve this result but unfortunately Google Sheets QUERY language is not as expressive. That's why the resulting formula looks a bit confusing.
=query(
IMPORTRANGE("https://docs.google.com/spreadsheets/d/1LoHg53hzQvYtOLTcDwxLY8OrKVN4F7usX8YI41BtdWg/edit","Activity list!A:E"),
"select Col1, Col2, Col3, Col4, Col5
where Col1= date'"&
JOIN("' or Col1 = date '",
ARRAYFORMULA(TEXT(ARRAY_CONSTRAIN(
query(query(
"THE IMPORTED RANGE",
"select Col1,Col2,Col3,Col4,Col5
where Col1> date '"&TEXT(I2,"yyyy-mm-dd")&"' and Col2 = '"&I3&"'
order by Col1 desc",1),
"select MAX(Col1), Col4
group by Col4
order by MAX(Col1) desc
label MAX(Col1) ''", 0),
1000, 1),
"yyyy-MM-DD")
))&"'",1)
Queries specification starting from the inner one:
Filter the data with your criteria.
Get the most recent submission grouping by Client.
Join the results with the whole dataset to fetch the other column values.
Use the ARRAY_CONSTRAIN formula to retrieve the columns with the dates.
The same approach goes for the oldest submission changing MAX for MIN aggregate function.
Note: This is not suited for daily multiple submissions.
I think the easiest way to do this is using a Vlookup into a query(). unfortunately, it involves using the IMPORTRANGE() twice, but I still think it's more efficient than some other possible methods. You'll find it in A2 of the MK.Help tab on your sample sheet.
=ARRAYFORMULA(IFERROR(VLOOKUP(UNIQUE(query(IMPORTRANGE("1LoHg53hzQvYtOLTcDwxLY8OrKVN4F7usX8YI41BtdWg","Activity list!A:E"), "select Col4 where Col1> date '"&TEXT(I2,"yyyy-mm-dd")&"' and Col2 = '"&I3&"'
order by Col1 desc",1)),query(IMPORTRANGE("1LoHg53hzQvYtOLTcDwxLY8OrKVN4F7usX8YI41BtdWg","Activity list!A:E"), "select Col4,Col1,Col2,Col3,Col5 where Col1> date '"&TEXT(I2,"yyyy-mm-dd")&"' and Col2 = '"&I3&"'
order by Col1 desc",1),{2,3,4,1,5},0)))

Deletting duplicate data on oracle using sql failed

I have a table abc as:
acc subgroup
720V A
720V A
720V A
720V A
111 C
222 D
333 E
My expected output is:
acc subgroup
720V A
111 C
222 D
333 E
Since 720V A is duplicate i want to delete all three duplicate data and only want one data in my table.
So,i tried
DELETE FROM (
select t.*,rownum rn from abc t where acc='720V') where rn>1;
So,I get error as:
ORA-01732: data manipulation operation not legal on this view
How i can get my expected output?
Your table seems to be lacking a primary key column, which is a big problem here. Assuming there actually is a primary key column PK, we can try using ROW_NUMBER to identify any "duplictes":
DELETE
FROM abc t1
WHERE pk IN (SELECT pk
FROM (
SELECT t.pk, ROW_NUMBER() OVER (PARTITION BY acc, subgroup ORDER BY pk) rn
FROM abc t) x
WHERE rn > 1
);
Note that if you can live with keeping your original data, then the most expedient thing to do might be to create a distinct view:
CREATE VIEW abc_view AS
SELECT DISTINCT acc, subgroup
FROM abc;

Tune oracle query with groupby clause

I have a table with Lots of cost columns for each Key
TableA
SK1 SK2 Col1 Col2 Col3..... Col50 Flg(Y/N)
1 2 10 20 30 ...... 500 Y
1 2 10 20 30 ...... 500 N
2 2 10 20 30 ...... 500 N
I need to aggregate(sum) of all values and then check if there are any values with Y then add them to new tableB.
Here table A record combination (1,2) for (sk1,sk2) should be returned.
The i have written query is to select lisr of all cols and add as group by.
We have lots of data so this query is taking too long to run. Any chance to relook into this and do so that it can become faster.
select
Sk1,
Sk2,
nvl(sum(col3),0),
nvl(sum(col4))0,
.....
nvl(sum(col50))
from table A
group by Sk1,
Sk2
Iam using this as part of large query where in many other calculations are performed on top of this.
Working out whether any of a grouped set of records contains a 'Y' would be as simple as ...
select ...
from ...
group by ...
having max(flg) = 'Y'
For now i have created a temporary table and have loaded all the data into it.
If you are using this as part of large query, did you try WITH option?
It could be like this
WITH SUM_DATA AS (select col1, col2, nvl(sum(col3),0), nvl(sum(col4))0, ..... nvl(sum(col50)) from table A group by col1, col2)
SELECT xyz
FROM abc, sum_data
WHERE abc.join_col = sum_data.join_col
More help here

Resources