Count all data even with zero/0 value - oracle

I have data like this
product location
snack america
snack brazil
biscuit america
biscuit china
biscuit japan
soda brazil
soda japan
soda india
what I want is like below, however I can do it differently using pivot, but is is possible to have the data like this?
location product count
america snack 1
america biscuit 1
america soda 0
brazil snack 1
brazil biscuit 0
brazil soda 1
japan snack 0
japan biscuit 1
japan soda 1

We can generate a "calendar" table of all product/location combinations, via a cross join:
SELECT
loc.location,
prod.product,
CASE WHEN t.location IS NULL THEN 0 ELSE 1 END AS count
FROM (SELECT DISTINCT location FROM yourTable) loc
CROSS JOIN (SELECT DISTINCT product FROM yourTable) prod
LEFT JOIN yourTable t
ON t.location = loc.location AND
t.product = prod.product
ORDER BY
loc.location,
prod.product;
Demo

Please elaborate our concern, the result table that you are asking could be generated but specify your concern in a detail manner

Related

How to categorize data in a ORACLE table based on a primary key?

I have a table TRAVEL with column TRIP_ID as primary key.
SOURCE DATA
TRIP_ID PERSON_NAME DESTINATION SOURCE TRANSACTION_ID TRIP_COUNT
100 Mike London Zurich 1000B112 1
101 Mike Paris Capetown 1000B112 1
102 Mike Moscow Madrid 1000B112 1
103 John Delhi Moscow 1100A110 1
104 John Toronto Zurich 1100A110 1
105 Mary Chennai Madrid 1100A111 1
106 Mary Berlin Zurich 1100A111 1
EXPECTED RESULTS:
when I do select * from TRAVEL where TRANSACTION_ID = 1100A111 it returns below two rows as below .
so I want my data to be categorized based on the transaction_ID on a run time.I dont want to hardcode the value for transaction-ID each time as above but i want to group it in such a way that it should fetch me the above expected results.I mean it should return all the data which are corresponding to the TransactionID in the table and it should not sum up the TRIP COUNT.It should return me the rows as below in my table.I am ok to create view .Please suggest
TRIP_ID PERSON_NAME DESTINATION SOURCE TRANSACTION_ID TRIP_COUNT
105 Mary Chennai Madrid 1100A111 1
106 Mary Berlin Zurich 1100A111 1
Can someone suggest a query in ORACLE to handle this ? I donot want to hardcode transaction ID
Regards
Sameer

Oracle Query Prevent Displayed Duplicate Record

Let's say i have a table structure like this :
ID | Name | SCHOOLNAME | CODESCHOOL
1 DARK Kindergarten 123 1
2 DARK Kindergarten 111 1
3 Knight NY University 3
4 Knight LA Senior HS 2
5 JOHN HARVARD 3
so, how to diplay all of the data above into like this :
ID | Name | SCHOOLNAME | CODESCHOOL
1 DARK Kindergarten 123 1
3 Knight NY University 3
5 JOHN HARVARD 3
my purpose is want to display data with the max of codeschool, but when i tried with my query below :
SELECT NAME, SCHOOLNAME, MAX(CODESCHOOL) FROM TABLE GROUP BY NAME, SCHOOLNAME
but the result is just like this :
ID | Name | SCHOOLNAME | CODESCHOOL
1 DARK Kindergarten 123 1
2 DARK Kindergarten 111 1
3 Knight NY University 3
4 Knight LA Senior HS 2
5 JOHN HARVARD 3
maybe it caused by the GROUP BY SCHOOLNAME, when i tried to not select SCHOOLNAME, the data displayed just like what i expected, but i need the SCHOOLNAME field for search condition in my query
hope you guys can help me out of this problem
any help will be appreciated
thanks
Using some wacky joins you can get a functional get max rows per category query.
What you essentially need to do is to join the table to itself and make sure that the joined values only contain the top values for the CODESCHOOL column.
I've also added a :schoolname parameter because you wanted to search by schoolname
Example:
SELECT
A.*
FROM
TABLE1 A
LEFT OUTER JOIN TABLE1 B ON B.NAME = A.NAME
AND B.CODESCHOOL < A.CODESCHOOL
WHERE
B.CODESCHOOL IS NULL AND
(
(A.SCHOOLNAME = :SCHOOLNAME AND :SCHOOLNAME IS NOT NULL) OR
(:SCHOOLNAME IS NULL)
);
this should create this output, note that dark has 2 outputs because it has 2 rows with the same code school which is the max in the dark "category"/name.
ID|NAME |SCHOOLNAME |CODESCHOOL
--| -----|----------------|----------
4|Knight|LA Senior HS | 2
5|JOHN |HARVARD | 3
2|DARK |Kindergarten 111| 1
1|DARK |Kindergarten 123| 1
It's not the most effective query but it should be more than good enough as a starting point.
Sidenote: I've been blatantly stealing this logic for a while from https://www.xaprb.com/blog/2007/03/14/how-to-find-the-max-row-per-group-in-sql-without-subqueries/
I am using an analytical window function ROW_NUMBER().
This will group (or partition) by NAME then select the top 1 CODESCHOOL in DESC order.
Select NAME,
SCHOOLNAME,
CODESCHOOL
From (
Select NAME,
SCHOOLNAME,
CODESCHOOL,
ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY CODESCHOOL DESC) as rn
from myTable)
Where rn = 1;

Oracle merge into with text similarlity

I have 2 tables: from_country and to_country. I want to bring new records and update records to to_country
Definition and data
--
CREATE TABLE from_country
(
country_code varchar2(255) not null
);
--
CREATE TABLE to_country
(
country_code varchar2(255) not null
);
-- Meaning match
INSERT INTO from_country
(country_code)
VALUES
('United States of America');
-- Match 100%
INSERT INTO from_country
(country_code)
VALUES
('UGANDA');
-- Meaning match, but with domain knowledge
INSERT INTO from_country
(country_code)
VALUES
('CON CORRECT');
-- Brand new country
INSERT INTO from_country
(country_code)
VALUES
('NEW');
--
INSERT INTO to_country
(country_code)
VALUES
('USA');
-- Match 100%
INSERT INTO to_country
(country_code)
VALUES
('UGANDA');
-- Meaning match, but with domain knowledge
INSERT INTO to_country
(country_code)
VALUES
('CON');
I need to run merge into so I bring data from from_county to to_country
Here is my 1st attempt, but it only does a equal, which is not good enough. I need some smartness so that it is able to do meaning match.
If anyone know how to do it, please provide your solution.
merge into
to_country to_t
using
from_country from_t
on
(to_t.country_code = from_t.country_code)
when not matched then insert (
country_code
)
values (
from_t.country_code
);
So in a nutshell, here is what I want
from_table:
United States of America
UGANDA
CON CORRECT
NEW
to_table:
USA
UGANDA
CON
After oracle merge into
the new to_country table:
United States of America
UGANDA
CON CORRECT
NEW
sql fiddle: http://sqlfiddle.com/#!4/f512d
Please note that this is my simplified example. I have larger data set.
Since the match is not guaranteed unique, you have to write a query that will return only one match using some decision.
Here is a simplified case which uses a naive match and then just picks one value when there is more than one match:
merge into to_country t
using (
select * from (
select t.rowid as trowid
,f.country_code as fcode
,t.country_code as tcode
,case when t.country_code is null then 1 else
row_number()
over (partition by t.country_code
order by f.country_code)
end as match_no
from from_country f
left join to_country t
on f.country_code like t.country_code || '%'
) where match_no = 1
) s
on (s.trowid = t.rowid)
when matched then update set country_code = s.fcode
when not matched then insert (country_code) values (s.fcode);
Result in to_country:
USA
UGANDA
CON CORRECT
United States of America
Now that that's taken care of, you just need to make the match algorithm smarter. This is where you need to look at the whole dataset to see what sort of errors there are - i.e. typos, etc.
You could try some of the procedures in Oracle's supplied UTL_MATCH for this purpose: https://docs.oracle.com/cd/E18283_01/appdev.112/e16760/u_match.htm - such as EDIT_DISTANCE, or JARO_WINKLER.
Here is an example using the Jaro Winkler algorithm:
merge into to_country t
using (
select * from (
select t.rowid as trowid
,f.country_code as fcode
,t.country_code as tcode
,case when t.country_code is null then 1
else row_number() over (
partition by t.country_code
order by utl_match.jaro_winkler_similarity(f.country_code,t.country_code) desc)
end as match_no
from from_country f
left join to_country t
on utl_match.jaro_winkler_similarity(f.country_code,t.country_code) > 70
) where match_no = 1
) s
on (s.trowid = t.rowid)
when matched then update set country_code = s.fcode
when not matched then insert (country_code) values (s.fcode);
SQL Fiddle: http://sqlfiddle.com/#!4/f512d/23
Note that I've picked an arbitrary cutoff of >70%. This is because UGANDA vs. USA has a Jaro Winkler similarity of 70.
This results in the following:
United States of America
USA
UGANDA
CON NEW
To see how these algorithms fare, run something like this:
select f.country_code as fcode
,t.country_code as tcode
,utl_match.edit_distance_similarity(f.country_code,t.country_code) as ed
,utl_match.jaro_winkler_similarity(f.country_code,t.country_code) as jw
from from_country f
cross join to_country t
order by 2, 4 desc;
FCODE TCODE ED JW
======================== ====== === ===
CON NEW CON 43 86
CON CORRECT CON 28 83
UGANDA CON 17 50
United States of America CON 0 0
UGANDA UGANDA 100 100
United States of America UGANDA 9 46
CON NEW UGANDA 15 43
CON CORRECT UGANDA 0 41
UGANDA USA 34 70
United States of America USA 13 62
CON CORRECT USA 0 0
CON NEW USA 0 0
SQL Fiddle: http://sqlfiddle.com/#!4/f512d/22

How to create a sequence number based on my result set?

This is how my table currently looks
Month Product Value
---------------------------------
1 Shoes 12.00
1 Jacket 15.00
2 Shirt 3.00
I need to add a column that generates a MonthlySaleID that increments for each month and resets each time the month changes, like so
Month Product Value MonthlySaleID
------------------------------------------------
1 Shoes 12.00 1
1 Jacket 15.00 2
2 Shirt 3.00 1
Any clues would be great
You can try with this view then:
CREATE OR REPLACE VIEW vw_rpt_sales AS
SELECT month, product, value, RANK() OVER (PARTITION BY month ORDER BY Product) AS MonthlySaleID
FROM
originaltable;
Couldn't test the rank function, in theory it should return what you want. I ordered by Product because it didn't seem in your question that you had a sale ID information. But if you have it, it's better to order by SaleID I suppose.

How to run SQL query group by issue?

I have a table with columns :
Table Name: IdentityTable
ID Dest_Name Dest_Reference_Id Format IG
31231231 India Delhi XKHYGUI 21
12313131 USA Washington XHKOWKG 1
34645542 India Mumbai XKLWOFH 1
31231314 USA California XLGJDJG 21
31234531 India Delhi XKHIHUI 21
12375671 USA Washington XHKLHKG 21
12574613 USA Washington XLKWMKG 1
and so on...
I want to query this table to retrieve information in this form:
Dest_Name Dest_Reference_Id Total_Format Format IG
India Delhi 2 XKHYGUI 21
India Delhi 2 XKHIHUI 21
USA Washington 3 XHKOWKG 1
USA Washington 3 XHKLHKG 21
USA Washington 3 XLKWMKG 1
India Mumbai 1 XKLWOFH 1
USA California 1 XLGJDJG 21
I did:
select dest_name, dest_reference_id, count (format)
from IdentityTable
Group By dest_name, dest_reference_id;
I could retrieve all information required except Format column in the result. How should I modify my query to return expected result ?
Make two sub-queries and join em up.
SELECT counts.dest_name,
counts.dest_reference_id,
counts.total_format,
idents.format,
idents.IG
FROM
(
select dest_name, dest_reference_id, count (format) as total_format
from IdentityTable
Group By dest_name, dest_reference_id;
) counts
join
(
select distinct dest_name, dest_reference_id, format, IG
from identitytable
) idents
on counts.dest_name = idents.dest_name
and counts.dest_reference_id = idents.dest_reference_id
count(*) over(partition by dest_name, dest_reference_id)
and without a group by. google "oracle analytic functions".

Resources