I have a query where it generates 18 digit code.
Here is the logic for generating the 18 digit code.
R - Fix
AP – (GIS STATE refer B column from below table)
AP01- (SLP_STATE refer C column from below table)
SMT – (Format refer A Column from below table)
4567 – Store Code
with above logic the code generated is like this R-AN-SOUT--6715
With above 18 digit code, there is 2 error.
1.) For point no second in above logic, where it takes STATE column it only takes the first two digit of the state.
For ex: If the state name is Andhra Pradesh it takes AN but actually it should take AP. Also, if the state name for Mumbai it should take MU where it is taking MU which is correct.
2.) For point number second it is not taking the FORMAT may be due to left join which brings data from another column.
Here is below the query and its description.
SELECT 'R' ||'-'|| UPPER(SUBSTR(r.STATE, 1, 2)) ||'-'|| UPPER(SUBSTR(r.ZONE_NAME, 1, 4))
||'-'|| s.FORMAT_CODE ||'-'|| SUBSTR(r.STORE_CODE, 1,4)
FROM tbl_rrsoc_store_info r
LEFT JOIN tbl_site_store_format s
ON r.STORE_CODE = s.FORMAT_CODE
where r.STORE_CODE = '6715';
Also the table description
Table name:- TBL_RRSOC_STORE_INFO
Name Null Type
--------------------------- -------- --------------
RRSOC_ID NOT NULL NUMBER
STORE_CODE NOT NULL NVARCHAR2(55)
STATE NVARCHAR2(55)
SLP_STATE NVARCHAR2(100)
FORMAT_GROUP NVARCHAR2(100)
Table name:- TBL_SITE_STORE_FORMAT
Name Null Type
------------ ---- -------------
ID VARCHAR2(20)
STORE_FORMAT VARCHAR2(100)
ISACTIVE VARCHAR2(3)
FORMAT_GROUP VARCHAR2(100)
FORMAT_CODE VARCHAR2(50)
You are only selecting the first two characters of the state name. If you want the first letter of the second part of the name, you must code for it.
You are joining tbl_site_store_format on the wrong column, the value from each table should be store_code.
SELECT 'R_'
|| CASE
WHEN INSTR (TRIM (r.state), ' ') > 1
THEN
SUBSTR (r.state, 1, 1)
|| SUBSTR (r.state, INSTR (r.state, ' ') + 1, 1)
ELSE
UPPER (SUBSTR (r.state, 1, 2))
END
|| '-'
|| UPPER (SUBSTR (r.zone_name, 1, 4))
|| '-'
|| s.format_code
|| '-'
|| SUBSTR (r.store_code, 1, 4)
FROM tbl_rrsoc_store_info r
LEFT JOIN tbl_site_store_format s ON r.store_code = s.store_code
Related
I have a given database-table where I am not able to change the database-design.
This table contains a column whare names are saved.
The Column "UserName" contains values like "Clinton Bill" or "Trump Donald" or "Bush George".
I need a select statement which is able to find the primary key for the "Bill Clinton" or "Donald Trump"-row.
So the order of Firstname and Lastname is reversed.
Does anybody know how this can be done.
How the Where-Clouse should look like.
If you want to "reverse" such a string (that contains of two words), you can use substr + instr or regular expressions, e.g.
SQL> with test (username) as
2 (select 'Clinton Bill' from dual)
3 select substr(username, instr(username, ' ') + 1) ||' '||
4 substr(username, 1, instr(username, ' ') - 1) as reversed_value,
5 --
6 regexp_substr(username, '\w+', 1, 2) ||' '||
7 regexp_substr(username, '\w+', 1, 1) as reversed_value_2
8 from test;
REVERSED_VALUE REVERSED_VALUE_2
-------------------- --------------------
Bill Clinton Bill Clinton
SQL>
Now, just re-use it (whichever option you want) in another query, e.g.
select id
from test
where regexp_substr(username, '\w+', 1, 2) ||' '||
regexp_substr(username, '\w+', 1, 1) = 'Bill Clinton'
I have some SQL that pulls back data from a number of places and then shows it in one row, two cells. In each of the cells is a list of the data. If I break down the SQL, Originally the data would show like this:
Name
Colortype
Orange
Gold
Yellow
Banana [CHR(10)] Gold
Sorry for the weird table, but basically Name column has one value per row, but Colortype can have 0 to many values. The issue in my SQL is the ColorType field is a blob list of values that has been separated by a newline CHR(10). So under Yellow Name, the colortype contains Banana separated by a newline and Gold. But you can also see that Name:Orange also has a Gold colortype.
In the end of my SQL I am taking the individual rows and rolling up so that in the end I get one row, each column containing a list of values using this..
SELECT distinct RTRIM(XMLAGG(XMLELEMENT(E, (myTableX.uo_unicode_to_sch (colortype)), CHR (10) ).EXTRACT('//text()') ORDER BY pct_vu).GetClobVal(),',') as risk_tx,
RTRIM(XMLAGG(XMLELEMENT(E, myTableY.uo_unicode_to_sch (name)), CHR(10)).EXTRACT('//text()') ORDER BY pct_vu desc).GetClobVal(),',') AS name
Which gives me one row, the names with it's already unique 19 values. And the colortype, with it's list of 1+x non-unique values. Like this but instead of spaces between values in the cell, they are newlines.
Name
Colortype
Orange Yellow
Gold Banana Gold
This is most of the original sql:
SELECT *
FROM (SELECT distinct to_char(colortype), name
FROM (SELECT DISTINCT DBMS_LOB.substr(x.name, 4000) as name ,
DBMS_LOB.substr(x.colortype, 4000, 1) as colortype
FROM (SELECT distinct RTRIM(XMLAGG(XMLELEMENT(E, (myTableA.uo_unicode_to_A (colortype)), CHR (10) ).EXTRACT('//text()') ORDER BY w).GetClobVal(),',') as colortype,
RTRIM(XMLAGG(XMLELEMENT(E, myTableA.uo_unicode_to_A (name)|| ' ' || CASE WHEN w < 0.1 THEN '< 0.1' ELSE TRIM (TO_CHAR (w, CASE WHEN w < 1 THEN '0.9' ELSE '999'END)) END
|| '%', CHR (10)).EXTRACT('//text()') ORDER BY w desc).GetClobVal(),',') AS name,
RTRIM(XMLAGG(XMLELEMENT(E,CHR (13) , CHR (10) ).EXTRACT('//text()') ).GetClobVal(),',') AS rz
FROM (SELECT MAX (CASE WHEN z.item_type = 'Name' THEN z.value_tx END) AS name,
MAX (CASE WHEN z.item_type = 'Exact %' THEN TO_NUMBER(REGEXP_SUBSTR(z.value_tx,'^\d+')) END) AS w,
MAX (CASE WHEN z.item_type = 'Class' THEN z.value_tx END) AS colortype
FROM myTableA.product p
JOIN TABLE (myTableA.z_data.get_unique_name ('r#'|| TO_CHAR (p.prod_id)))z
ON z.country_cd = 'US' AND z.locale_cd = 'en' AND z.section_vu = 3
AND z.item_type IN ('Name','Exact %','Class')
GROUP BY z.sub_section_nm))x
JOIN TABLE (CAST (MULTISET(SELECT LEVEL FROM DUAL CONNECT BY LEVEL <=(LENGTH (x.colortype)- LENGTH (REPLACE (x.colortype,x.rz)))
/ LENGTH (x.rz) + 1) AS SYS.odcinumberlist)) y
ON 1 = 1
)
);
I cannot provide the full sql, but what I'm looking for is anyone's thoughts on how to distinct a clob field in the end? I am using 12.1 Oracle.
Both methods below use LISTAGG so if you are going to have more than 4000 characters in your result, you may need to find an alternate method of aggregation.
Since you are on Oracle 12.1, you will need a query like this:
WITH
colors
AS
(SELECT 'Orange' AS name, 'Gold' AS colortype FROM DUAL
UNION ALL
SELECT 'Yellow', 'Banana' || CHR (10) || 'Gold' FROM DUAL),
split_colors
AS
(SELECT name, COLUMN_VALUE AS color
FROM colors c
CROSS JOIN
TABLE (
CAST (
MULTISET (
SELECT SUBSTR (TRIM (REGEXP_SUBSTR (c.colortype,
'[^' || CHR (10) || ']+',
1,
LEVEL)),
1,
4000)
FROM DUAL
CONNECT BY LEVEL <=
REGEXP_COUNT (c.colortype, '[^' || CHR (10) || ']+'))
AS SYS.ODCIVARCHAR2LIST)) c1)
SELECT (SELECT LISTAGG (name, CHR (10)) WITHIN GROUP (ORDER BY name)
FROM (SELECT DISTINCT name
FROM split_colors)) AS names,
(SELECT LISTAGG (color, CHR (10)) WITHIN GROUP (ORDER BY color)
FROM (SELECT DISTINCT color
FROM split_colors)) AS colors
FROM DUAL;
If you were on Oracle 19c, you could use LISTAGG DISTINCT
WITH
colors
AS
(SELECT 'Orange' AS name, 'Gold' AS colortype FROM DUAL
UNION ALL
SELECT 'Yellow', 'Banana' || CHR (10) || 'Gold' FROM DUAL),
split_colors
AS
(SELECT name, COLUMN_VALUE AS color
FROM colors c
CROSS JOIN
TABLE (
CAST (
MULTISET (
SELECT SUBSTR (TRIM (REGEXP_SUBSTR (c.colortype,
'[^' || CHR (10) || ']+',
1,
LEVEL)),
1,
4000)
FROM DUAL
CONNECT BY LEVEL <=
REGEXP_COUNT (c.colortype, '[^' || CHR (10) || ']+'))
AS SYS.ODCIVARCHAR2LIST)) c1)
SELECT LISTAGG (DISTINCT name, CHR (10)) WITHIN GROUP (ORDER BY name) AS names,
LISTAGG (DISTINCT color, CHR (10)) WITHIN GROUP (ORDER BY color) AS colors
FROM split_colors;
Have to compare the data differences between the below two tables. I have achieved this by writing a MINUS query but that does not fit for current assignment. Because few tables have 50- 60 columns and each time have to mention the columns before execution.
I have followed Expert's response and not succeeded in achieving the goal. Basically I want to write a procedure which:
Accepts both table names as parameters.
Fetch all the columns of CustomerTable.
Then MINUS query between CustomerTable and StagingCustTable only with the columns fetched in step-2.
Logging any differences.
CustomerTable
Custromer_Number
Address
order_Number
Contact
Country
Post_Code
Amount
StagingCustTable
Custromer_Number
Address
order_Number
Contact
Country
Post_Code
Amount
Run_Id
Record_Id
I would not use a procedure but a query to generate a final query.
Kind of dynamic SQL.
Simple example - let say we have the following tables and data in them:
CREATE TABLE CustomerTable(
Custromer_Number int,
Address varchar2(100),
order_Number int,
Contact int,
Country varchar2(10),
Post_Code varchar2(10),
Amount number
);
INSERT ALL
INTO CustomerTable VALUES (1, 'aaa', 1, 1, 'AA', '111', 111.11 )
INTO CustomerTable VALUES (2, 'bbb', 2, 2, 'BB', '222', 222.22 )
SELECT 1 FROM dual;
CREATE TABLE StagingCustTable
AS SELECT t.*, 1 As run_id, 1 as record_id
FROM CustomerTable t
WHERE 1=0;
INSERT ALL
INTO StagingCustTable VALUES (1, 'aaa', 1, 1, 'AA', '111', 111.11, 1, 1 )
INTO StagingCustTable VALUES (3, 'ccc', 3, 3, 'CC', '333', 333.33, 3, 3 )
SELECT 1 FROM dual;
commit;
Now when you run this simple query:
SELECT 'SELECT ' || listagg( column_name, ',' ) WITHIN GROUP ( ORDER BY column_id )
|| chr(10) || ' FROM ' || max( table_name )
|| chr(10) || ' MINUS '
|| chr(10) || 'SELECT ' || listagg( column_name, ',' ) WITHIN GROUP ( ORDER BY column_id )
|| chr(10) || ' FROM StagingCustTable ' as MySql
FROM user_tab_columns
WHERE table_name = upper( 'CustomerTable' );
you will get the following result:
MYSQL
-------------------------------------------------------------------------
SELECT CUSTROMER_NUMBER,ADDRESS,ORDER_NUMBER,CONTACT,COUNTRY,POST_CODE,AMOUNT
FROM CUSTOMERTABLE
MINUS
SELECT CUSTROMER_NUMBER,ADDRESS,ORDER_NUMBER,CONTACT,COUNTRY,POST_CODE,AMOUNT
FROM StagingCustTable
Now just copy the above query, paste it to your SQL client, run it - and the task is done in a few minutes.
If input is comma separated then store the first part in LAST_NAME and second part in FIRST_NAME.
If comma is not present then store the name in LAST_NAME
Can you please help me in achieving the #2 in oracle?
In my approach am unable to store the full_name in last_name column if there is no comma.
Input :
1. FULL_NAME = "MIKE,MYERS"
2. FULL_NAME = "KFC"
Output :
SELECT SUBSTR('FULL_NAME', 0, INSTR('1,2', ',') - 1) LAST_NAME,
SUBSTR('FULL_NAME', INSTR('1,2', ',', -1) + 1) FIRST_NAME FROM DUAL
**LAST_NAME** **FIRST_NAME**
MIKE MYERS
**LAST_NAME** **FIRST_NAME**
KFC
Since you need two separate columns, I think you would need two CASE statements.
For example,
SQL> WITH DATA AS
2 ( SELECT 'MIKE,MYERS' str FROM dual
3 UNION ALL
4 SELECT 'KFC' str FROM dual
5 )
6 SELECT
7 CASE
8 WHEN instr(str, ',') <> 0
9 THEN SUBSTR(str, 1, INSTR(str, ',', 1) - 1)
10 ELSE str
11 END LAST_NAME,
12 CASE
13 WHEN instr(str, ',') <> 0
14 THEN SUBSTR(str, INSTR(str, ',', 1) +1)
15 ELSE NULL
16 END FIRST_NAME
17 FROM DATA
18 /
LAST_NAME FIRST_NAME
---------- ----------
MIKE MYERS
KFC
SQL>
I have a table with two columns that might be null (as well as some other columns). I would like to count how many rows that have column a, b, both and neither columns set to null.
Is this possible with Oracle in one query? Or would I have to create one query for each? Can't use group by or some other stuff I might not know about for example?
COUNT(expr) will count the number of rows where expr is not null, thus you can count the number of nulls with expressions like these:
SELECT count(a) nb_a_not_null,
count(b) nb_b_not_null,
count(*) - count(a) nb_a_null,
count(*) - count(b) nb_b_null,
count(case when a is not null and b is not null then 1 end)nb_a_b_not_null
count(case when a is null and b is null then 1 end) nb_a_and_b_null
FROM my_table
Something like this:
SELECT sum(case
when a is null and b is null then 1
else 0
end) as both_null_count,
sum(case
when a is null and b is not null then 1
else 0
end) as only_a_is_null_count
FROM your_table
You can extend that for other combinations of null/not null
select sum(decode(a,null,0,1)) as "NotNullCount", sum(decode(a,null,1,0)) as "NullCount"
from myTable;
Repeat for as many fields as you like.
It can be accomplished in Oracle just in 1 row:
SELECT COUNT(NVL(potential_null_column, 0)) FROM table;
Function NVL checks if first argument is null and treats it as value from second argument.
This worked well for me for counting getting the total count for blank cells on a group of columns in a table in oracle: I added the trim to count empty spaces as null
SELECT (sum(case
when trim(a) is null Then 1
else 0
end)) +
(sum(case
when trim(b) is null
else 0
end)) +
(sum(case
when trim(c) is null
else 0
end)) as NullCount
FROM your_table
Hope this helps
Cheers.
SQL>CREATE TABLE SAMPLE_TAB (COL1 NUMBER NOT NULL, COL2 DATE DEFAULT SYSDATE, COL3 VARCHAR2(20));
SQL>INSERT INTO SAMPLE_TAB(COL1,COL2,COL3) VALUES(121,SYSDATE-2,'SAMPLE DATA');
SQL>INSERT INTO SAMPLE_TAB(COL1,COL2,COL3) VALUES(122,NULL,NULL); --ASSIGN NULL TO COL2
SQL>INSERT INTO SAMPLE_TAB(COL1,COL3) VALUES(123,'SAMPLE DATA RECORD 3');--COL2 DEFAULT VALUE ASSIGN AS SYSDDATE AS PER STRUCTURE.
SQL>COMMIT;
SQL> SELECT * FROM SAMPLE_TAB;
SQL> SELECT *
FROM USER_TAB_COLUMNS U
WHERE 1=1
AND TABLE_NAME='SAMPLE_TAB'
AND NUM_NULLS!=0;
SQL> ANALYZE TABLE SAMPLE_TAB COMPUTE STATISTICS;
SQL> SELECT *
FROM USER_TAB_COLUMNS U
WHERE 1=1
AND TABLE_NAME='SAMPLE_TAB'
AND NUM_NULLS!=0;
One way to do it would be:
select count(*) from table group by nvl2(a, 0, 1), nvl2(b, 0, 1) having nvl2(a,0,1) = nvl2(b,0,1);