(SQL) Renumber unique ids in a table - sql

I have receipt data with receipt numbers like this:
receipt_id item_id
123 321
123 322
123 323
124 321
124 322
125 321
125 323
I need to renumber the receipt_id so it looks like this:
receipt_id item_id
1 321
1 322
1 323
2 321
2 322
3 321
3 323
row_over or row_over partition by does not seem to get me what I want. I can do this by selecting distinct ids, renumber them, and then join them back. But there has to be a simpler, more correct way, or?

I think you can use DENSE_RANK() for this:
WITH T(receipt_id, item_id) AS(
VALUES
(123, 321),
(123, 322),
(123, 323),
(124, 321),
(124, 322),
(125, 321),
(125, 323)
)
SELECT DENSE_RANK() OVER(ORDER BY receipt_id) AS receipt_id, item_id
FROM T

Related

Insert into table only if select statement shows less than 2 rows

I have table like that:
id
document_id
category_id
is_main_category
1765
210
181
0
1764
210
179
1
1763
201
179
1
1762
209
181
0
1761
209
179
1
1754
211
182
0
1753
211
180
1
I need to select:
SELECT * FROM `documents` WHERE document_id = 210;
And if the number of rows is less than 2 I would like to insert into table one more row, like that:
INSERT INTO document_category (document_id, category_id, is_main_category)
VALUES (210, 181, 0);
Could you please help me to merge those 2 constructions.
Maybe you can build upon this:
INSERT INTO document_category (document_id, category_id, is_main_category)
SELECT 210, 181, 0
FROM documents
WHERE document_id = 210
GROUP BY document_id
HAVING COUNT(*) < 2;
If i understand you correctly, this should be what you looking for.
INSERT INTO
document_category(document_id, category_id, is_main_category)
SELECT
210, 181, 0
FROM
dual
WHERE
(SELECT COUNT(1) FROM documents WHERE document_id = 210) < 2;

Combine multiple records into one based on a condition

I want to combine each product_code's (comma-separated) in a single entry/record if all other values in multiple records are the same except the product_code
The dataset looks like below-
category_id subcat_id product_code customer_id quantity value
123 456 AB 111 2 1
123 456 CD 111 2 1
123 789 AB 111 2 2
123 789 CD 111 2 2
The result should look like-
category_id subcat_id product_code customer_id quantity value
123 456 AB,CD 111 2 1
123 789 AB,CD 111 2 2
Use string_agg();
select category_id, subcat_id, customer_id, quantity, value,
string_agg(product_code, ',')
from t
group by category_id, subcat_id, customer_id, quantity, value;
That said, I recommend arrays instead of strings for storing such values.

Oracle get latest value based on parent/child partition

I have a table named "customer" that looks like this:
ID ALPHA BRAVO CHARLIE DATE
-------------------------------------------------
1 111 222 333 02/02/2019
2 333 444 555 11/11/2019
3 666 555 777 12/12/2019
4 777 888 999 05/05/2020
5 100 101 110 12/25/2020
and I need to get the following output:
ID ALPHA BRAVO CHARLIE DATE NEW_COL ROW_NUM
-----------------------------------------------------------------------
1 111 222 333 02/02/2019 333 4
2 333 444 555 11/11/2019 333 3
3 666 555 777 12/12/2019 333 2
4 777 888 999 05/05/2020 333 1
5 100 101 110 12/25/2020 010 1
The ALPHA, BRAVO, and CHARLIE columns represent customer IDs. A given customer can have multiple IDs in the system. Records 1-4 represent IDs belonging to the same customer, let's say John. As per the table, John has 12 IDs, and his latest ID is 999. Record 5 represents another customer, let's say Jane. Jane has three IDs, and her last ID is 110.
The purpose of the ROW_NUM column is to get the last CUSTOMER.CHARLIE value. The idea is to use the first CHARLIE value as the partition. Basically, the goal is to get one parent:many children mapping. In this case, the ID 333 should be tied to 555, 777, and 999.
Here is the DDL/DML:
CREATE TABLE CUSTOMER
(ID NUMBER(20) NOT NULL,
ALPHA NUMBER(20) NOT NULL,
BRAVO NUMBER(20) NOT NULL,
CHARLIE NUMBER(20) NOT NULL,
CREATEDDATE DATE
);
INSERT INTO CUSTOMER
VALUES
(1, 111, 222, 333, to_date('02-FEB-19','DD-MON-RR'));
INSERT INTO CUSTOMER
VALUES
(2, 333, 444, 555, to_date('11-NOV-19','DD-MON-RR'));
INSERT INTO CUSTOMER
VALUES
(3, 666, 555, 777, to_date('12-DEC-19','DD-MON-RR'));
INSERT INTO CUSTOMER
VALUES
(4, 777, 888, 999, to_date('05-MAY-20','DD-MON-RR'));
INSERT INTO CUSTOMER
VALUES
(5, 100, 101, 110, to_date('25-DEC-20','DD-MON-RR'));
COMMIT;
I have tried the following query, but it fails to populate the partition column correctly:
WITH
charlies
AS
(SELECT DISTINCT charlie
FROM customer),
mult_customers
AS
(SELECT c.*, c.charlie AS NEW_COL
FROM customer c
UNION
SELECT c.*,
CASE WHEN c.alpha = e.charlie THEN c.alpha ELSE c.bravo END AS NEW_COL
FROM customer c
JOIN charlies e ON e.charlie = c.alpha OR e.charlie = c.bravo),
ranked
AS
(SELECT mc.*,
ROW_NUMBER ()
OVER (PARTITION BY NEW_COL ORDER BY createddate DESC) AS row_num
FROM mult_customers mc)
SELECT *
FROM ranked
ORDER BY ID;
Thanks for any help provided.
You task is known as connected components. I wrote about 7-8 years ago solution for this and even pl/sql package: http://orasql.org/2017/09/29/connected-components/
This PL/SQL solution is much more effective then pure SQL solutions: http://orasql.org/2014/02/28/straight-sql-vs-sql-and-plsql/
Let me know if you need help with adopting it for your task.

calculate Count and Sum from two different table with group by without using inner query

I have two table first A having column id,phone_number,refer_amount
and second B having column phone_number,transaction_amount
now i want sum() of refer_amount and transaction_amount and count() of phone_number from both table using group by phone_number without using inner query
Table A
phone_number refer_amount
123 50
456 80
789 90
123 90
123 80
123 20
456 20
456 79
456 49
123 49
Table B
phone_number transaction_amount
123 50
123 51
123 79
456 22
456 11
456 78
456 66
456 88
456 88
456 66
789 66
789 23
789 78
789 46
i have tried following query but it gives me wrong output:
SELECT a.phone_number,COUNT(a.phone_number) AS refer_count,SUM(a.refer_amount) AS refer_amount,b.phone_number,COUNT(b.phone_number) AS toal_count,SUM(b.transaction_amount) AS transaction_amount FROM dbo.A AS a,dbo.B AS b WHERE a.phone_number=b.phone_number GROUP BY a.phone_number,b.phone_number
output (wrong):
phone_number refer_count refer_amount phone_number transaction_count transaction_amount
123 15 867 123 15 900
456 28 1596 456 28 1676
789 5 450 789 5 291
output (That I want):
phone_number refer_count refer_amount phone_number transaction_count transaction_amount
123 5 289 123 3 180
456 4 228 456 7 419
789 1 90 789 5 291
I would do the aggregations on the B table in a separate subquery, and then join to it:
SELECT
a.phone_number,
COUNT(a.phone_number) AS a_cnt,
SUM(a.refer_amount) AS a_sum,
COALESCE(b.b_cnt, 0) AS b_cnt,
COALESCE(b.b_sum, 0) AS b_sum
FROM A a
LEFT JOIN
(
SELECT
phone_number,
COUNT(*) AS b_cnt,
SUM(transaction_amount) AS b_sum
FROM B
GROUP BY phone_number
) b
ON a.phone_number = b.phone_number;
One major potential issue with your current approach is that the join could result in duplicate counting, as a given phone_number record in the A table gets replicated due to the join.
Speaking of joins, note that above I use an explicit join, rather than the implicit one you were using. In general, you should not put commas into the FROM clause.
This can help. You don't need sum(b.phone_number) when checking for a.phone_number = b.phone_number. Distinct is needed for phone number as there are two columns to consider.
For group by, anything not in aggregate function needs to be in group by function.
select a.phone_number, count(distinct a.phone_number), sum(a.refer_amount),
sum (b.transaction_amount)
from A as a, B as b
where a.phone_number=b.phone_number
group by a.phone_number

Query for replacing data if the value is not number

I have a similar problem like this thread but is bit different what it required
https://community.oracle.com/thread/4132183
I have the following table:
Table1:
ID empID employeeactive dtefrom dateto mgrid
1 123 1 1/10/2016 113
2 213 0 1/20/2015 1/20/2016 323
3 213 1 1/20/2016 423
4 312 0 1/05/2016 1/30/2017 523
5 512 1 1/30/2017 623
6 812 1 2/30/2017 6543
Table2:
empID emplyactive supid
123 1 -
213 1 -
312 1 -
512 0 -
612 1 -
712 1 -
812 1 872
912 0 222
I have this table instead of - i want to replace with mgrid in table 1.. and table2 have extra data which is not in table1 so i have to ignore the extra data if supid '-' and also want to have emplyactive =1 but some of the emplyactive=1 table 1 has multiple mgr id ...
so I tried this one
select empid , decode(supid,'-',mgrid,supid) from table2,table1 where
empid(+) = empid and emplyactive =1 and employeeactive=1
so I am getthing how to solve this please help me out thank you .. if some thing like and exists will work thanks in advance.
This is what I am trying to insert in a package body oracle.
This is how the output looks like:
empID emplyactive supid
123 1 113
213 1 423
812 1 872
select a.empid, a.emplyactive, max(a.supid) supid
from (
select * from #table2
union
select empid, employeeactive, mgrid from #table1)a
left join #table1 b on a.empid=b.empid and employeeactive=1
join #table2 c on a.empid=c.empid and c.emplyactive=1
where a.emplyactive=1
and a.supid<>0
group by a.empid, a.emplyactive