Combine multiple records into one based on a condition - sql

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.

Related

More than one occurrence from table

create table customer (cif number, name varchar(20),mobile number);
insert into table customer values(121,'ANT',789);
insert into table customer values(122,'ANT',789);
insert into table customer values(123,'ENT',789);
insert into customer values(124,'ENT',789);
insert into customer values(125,'BEE',123);
insert into customer values(126,'BEE',123);
insert into customer values(127,'BRO',789);
insert into customer values(128,'FIO',789);
commit;
I want retrieve data from customer table based on name and mobile more than one occurrences.
Can anyone help me out
Result like
You can use COUNT() aggregation as Analytic function along with grouping by those columns through use of PARTITION BY clause as
SELECT cif, name, mobile
FROM (SELECT c.*,
COUNT(*) OVER (PARTITION BY name, mobile) AS cnt
FROM customer c )
WHERE cnt > 1
Demo
Source:
SQL> select * From customer;
CIF NAME MOBILE
---------- -------------------- ----------
121 ANT 789
122 ANT 789
123 ENT 789
124 ENT 789
125 BEE 123
126 BEE 123
127 BRO 789
128 FIO 789
8 rows selected.
Based on result you posted, you're looking for rows that aren't unique per name and mobile. If that's so, here's another option:
SQL> select *
2 from customer a
3 where exists (select null
4 from customer b
5 where b.name = a.name
6 and b.mobile = a.mobile
7 group by b.name, b.mobile
8 having count(*) > 1
9 );
CIF NAME MOBILE
---------- -------------------- ----------
121 ANT 789
122 ANT 789
123 ENT 789
124 ENT 789
125 BEE 123
126 BEE 123
6 rows selected.
SQL>

How to combine two fields and flag them accordingly

I would like to know how to flag customers who did not purchase some items that are described by two fields (product name and product number). I was able to perform this query for customers that did purchase them, but not the opposite. Thank you in advance for your help!
Here is part of my SQL query.
Select customer_id, product_name, product_number
from table
where
((PRODUCT_NAME = 'LIAM' AND PRODUCT_NUMBER = '212') OR
(PRODUCT_NAME = 'ARRAY' AND PRODUCT_NUMBER = '325')
)
Here is an example:
1 LIAM 212
1 STACY 452
1 NEIL 789
1 LIAM 345
2 ROSE 234
2 LIAM 345
2 ARRAY 325
3 STACY 452
3 ARRAY 625
Query Result:
1 ARRAY 325
2 LIAM 212
3 ARRAY 325
3 LIAM 212
You seems want not exists :
select t.*
from table t
where not exists (select 1
from table t1
where t1.customer_id = t.customer_id and
t1.PRODUCT_NAME in ('LIAM', 'ARRAY')
);
I don't see any advantage using of both Product_name and Product_number in the where clause if they are defined unique in table.
By this way, you will get customer's who never purchased liam or array product.

Postgres: Convert single rows from multiple tables into multiple rows in a single table

I have data scattered across multiple tables and rows that I'd like to aggregate into a more usable format for my use case. The problem boils down to something like this...
If I have two tables like this:
product_id title_id description_id
1 123 234
2 345 456
3 567 678
product_id additional_info_id
1 789
1 890
2 901
How would I construct a query to return data like this?
product_id content_id content_type
1 123 title
1 234 description
1 789 additional_info
1 890 additional_info
2 345 title
2 456 description
2 901 additional_info
3 567 title
3 678 Description
I found this post and I can construct a query like this
select
p.product_id,
p_content.*
from
product p,
lateral (values
(p.title_id, 'title'),
(p.description_id, 'description')
) p_content (content_id, content_type)
;
to get the data from the product table in the format I need, but I can't figure out how to incorporate the data from the additional_info table.
You can use union all:
select p.product_id, v.content_id, v.content_type
from product p cross join lateral
(values (p.title_id, 'title'),
(p.description_id, 'description')
) v(content_id, content_type)
union all
select product_id, additional_info_id, 'additional_info'
from additional_info ai;

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

SQL Count/sum multiple columns

I want to use count/ sum multiple fields in a single query sample data and desired result is as listed below:
MemID claimNum ItemID PaidAmt
123 1234 4 5
123 2309 4 5
123 1209 4 5
123 1209 8 2.2
123 1210 8 2.2
Desired result
MemID count(claimNum) count(ItemID) sum(PaidAmt)
123 3 3 15
123 2 2 4.4
It looks like you want to group by both MemID and ItemID:
select MemID, count(claimNum), count(ItemID), sum(PaidAmt)
from the_table
group by MemID, ItemID
Use group by ItemID
select MemID, count(claimNum), count(ItemID), sum(PaidAmt)
from my_table
group by MemID, ItemID