Oracle 11g count distinct products group by user - sql

I have a table with following fields
ID
PRODUCT
STATUS
USERID
Date
1
100
1
10
01-01-2023
2
101
1
10
01-01-2023
2
102
2
10
01-01-2023
3
100
2
20
02-01-2023
4
102
1
30
02-01-2023
4
100
1
10
03-01-2023
Desired output
Distinct product scan by each userid between 01-01-2023 to 03-01-2023 and count by status for each user
USERID
PRODUCT SCAN
STATUS1 CNT
STATUS2 CNT
10
3
2
1
20
1
0
1
30
1
1
0

Use COUNT(DISTINCT column_name).
Query
select userid, count(distinct product) as productScan
from table_name
where date between '2023-01-01' and '2023-01-03'
group by userid;

Related

Sum if same ID1 and ID2 - only once - SQL

I have the following data on SQL
EntryID
PersonID
JobID
JobSalary
1
1
1
270000
2
1
2
500000
3
2
3
320000
4
3
4
180000
5
2
3
320000
6
1
3
85000
7
1
1
270000
8
1
2
500000
9
2
3
320000
10
3
4
180000
For each entry, I want to have a column that calculates the total salary (of all jobs) of the specific person.
The tricky part is that multiple entries can refer to the same person and/or the same job, but I only want to sum up each job for each person once.
The output would be:
EntryID
PersonID
JobID
JobSalary
PersonTotalSalaryAllJobs
1
1
1
270000
855000
2
1
2
500000
855000
3
2
3
320000
320000
4
3
4
180000
180000
5
2
3
320000
320000
6
1
3
85000
855000
7
1
1
270000
855000
8
1
2
500000
855000
9
2
3
320000
320000
10
3
4
180000
180000
Any ideas on how to do this?
Thanks!
To get what you want you can use a query like this
SELECT
s.*,
pjts.total_salary
FROM salary s
LEFT JOIN (
SELECT
*,
SUM(jobsalary) OVER (PARTITION BY personid) AS total_salary
FROM (
SELECT DISTINCT
personid,
jobid,
jobsalary
FROM salary
) pjs
) pjts ON s.personid = pjts.personid AND s.jobid = pjts.jobid
You can check a working demo here
Or even simplier using only one subquery like this
SELECT
s.*,
pjts.total_salary
FROM salary s
LEFT JOIN (
SELECT
personid,
jobid,
SUM(jobsalary) OVER (PARTITION BY personid) AS total_salary
FROM salary
GROUP BY personid, jobid, jobsalary
) pjts ON s.personid = pjts.personid AND s.jobid = pjts.jobid
You can check a working demo here

sql best strategy to partition same values based on temporal sequence

I have data that looks like this, where there are multiple values for each ID that correspond to an ascending date variable:
ID LEVEL DATE
1 10 10/1/2000
1 10 11/20/2001
1 10 12/01/2001
1 30 02/15/2002
1 30 02/15/2002
1 20 05/17/2002
1 20 01/04/2003
1 30 07/20/2003
1 30 03/16/2004
1 30 04/15/2004
I want to acquire a count per each ID/LEVEL/DATE block that looks like this:
ID LEVEL COUNT
1 10 3
1 30 2
1 20 2
1 30 3
The problem is that if I use the count windows function and partition by level, it groups 30 together regardless of the temporal sequence. I want the count for level 30 both before and after 20 to be distinct. Does anyone know how to do that?
A standard gaps and islands solution using ROW_NUMBER(), if it's available on your particular DBMS...
WITH
ordered AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY date) AS set_ordinal,
ROW_NUMBER() OVER (PARTITION BY id, level ORDER BY date) AS grp_ordinal
FROM
yourData
)
SELECT
id,
level,
set_ordinal - grp_ordinal,
MIN(date),
COUNT(*)
FROM
ordered
GROUP BY
id,
level,
set_ordinal - grp_ordinal
ORDER BY
id,
MIN(date)
Visualising the effect of the two row numbers...
ID LEVEL DATE set_ordinal grp_ordinal set-grp GROUP
-- ----- ---------- ----------- ----------- ------- --------
1 10 10/01/2000 1 1 0 1,10,0
1 10 11/20/2001 2 2 0 1,10,0
1 10 12/01/2001 3 3 0 1,10,0
1 30 02/15/2002 4 1 3 1,30,3
1 30 02/15/2002 5 2 3 1,30,3
1 20 05/17/2002 6 1 5 1,20,5
1 20 01/04/2003 7 2 5 1,20,5
1 30 07/20/2003 8 3 5 1,30,5
1 30 03/16/2004 9 4 5 1,30,5
1 30 04/15/2004 10 5 5 1,30,5

SQL select latest values in a many-to-many table

How can I select latest records in a a table with many-to-many relationship. The store_id,product_id is not a composite group key so they repeat many times.
id store_id product_id
1 1 1
2 2 1
3 1 1
4 3 1
5 2 1
6 3 1
The result should be like this:
id store_id product_id
3 1 1
5 2 1
6 3 1
For the sake of simplicity I only added 1 product but in the real case there are many products. So the result should be something like :
For each store_id show the latest added products_id.
e.g.
id store_id product_id
11 1 1
20 1 2
40 1 3
41 1 4
53 2 1
61 2 2
62 2 3
63 2 4
70 3 1
71 3 2
72 3 3
73 3 4
I don't see what this has to do with a pivot table. This seems like a basic aggregation:
select max(id) as id, store_id, product_id
from t
group by store_id, product_id
order by store_id, max(id);

Multiply newly entered row with another column value and find Total Sum in SQL

I have 4 tables here, I need to multiply newly entered row value in a table with another row and find the total sum using CustomerId:
CustomerTable:
CustomerId Name EmailId
-------------------------
1 Paul r#r.com
2 John J#j.com
LoyaltyPointTable:
LoyaltyPointsId LoyaltyType Points
---------------------------------------
1 Registration 10
2 Loginstatus 1
3 Downloading 10
4 Redemming 1
5 Sharing 20
6 Refer 10
LoyaltyDetailsTable:
LoyaltyDetailsId LoyaltyPointsId CustomerId Dates
-------------------------------------------------
1 1 1 2015-01-22
2 2 1 2015-01-22
3 3 2 2015-01-22
4 3 1 2015-01-22
5 4 1 2015-01-22
6 4 1 2015-01-24
7 5 1 2015-01-24
This query works fine for the total sum for each LoyaltyType
SELECT
LoayaltyPointsTable.LoyaltyType,
COUNT(CustomerTable.CustomerId) AS UserActions,
SUM(LoayaltyPointsTable.Points) AS TotalPoints
FROM
LoayaltyPointsTable
JOIN
LoyaltyDetailsTable ON LoayaltyPointsTable.LoyaltyPointsId = LoyaltyDetailsTable.LoyaltyPointsId
JOIN
CustomerTable ON CustomerTable.CustomerId = LoyaltyDetailsTable.CustomerId
WHERE
CustomerTable.CustomerId = 1
GROUP BY
LoyaltyDetailsTable.CustomerId ,LoayaltyPointsTable.LoyaltyType
below RedeemPointsTable is created with relation to row redeeming in LoyaltyPointTable:
RedeemPointsTable:
RedeemPointsId CustomerId ShopName BillNo Amount
------------------------------------------------
1 1 Mall x 4757 100
3 1 Mall y SH43 50
4 1 Mall x 7743 10
6 1 Mall x s34a 60
What I am expecting is before calculating the total sum, I want column Amount sum (100+50+10+60) * 1 in Redeeming in LoyaltyPointTable to be added with total points for each CustomerId
Expected output
LoyaltyType UserActions TotalPoints
-------------------------------------
Downloading 1 10
Loginstatus 1 1
Redemming 4 (100+50+10+60)*1(here using Amount in RedeemPointsTable)
Refer 1 10
Registration 1 10
Sharing 1 20
User actions count is 4, it is based on the Amount he entered in RedeemPointsTable
Should I need to make changes in adding a foreign key column in RedeemPointsTable or can you point out my mistake?
Any help would be great.
This is the query which returns desired result:
SELECT
LoyaltyPointTable.LoyaltyType,
CASE
WHEN LoyaltyPointTable.LoyaltyPointsId=4 THEN (SELECT COUNT(amount) FROM RedeemPointsTable where CustomerId=1)
ELSE COUNT(CustomerTable.CustomerId)
END as UserActions,
CASE
WHEN LoyaltyPointTable.LoyaltyPointsId=4 THEN (SELECT SUM(amount) FROM RedeemPointsTable where CustomerId=1)*Points
ELSE SUM(LoyaltyPointTable.Points)
END as TotalPoints
FROM
LoyaltyPointTable
JOIN
LoyaltyDetailsTable ON LoyaltyPointTable.LoyaltyPointsId = LoyaltyDetailsTable.LoyaltyPointsId
JOIN
CustomerTable ON CustomerTable.CustomerId = LoyaltyDetailsTable.CustomerId
WHERE
CustomerTable.CustomerId = 1
GROUP BY
LoyaltyDetailsTable.CustomerId ,LoyaltyPointTable.LoyaltyType
You can check it here

Query for max to_date for one user id?

I am getting some unexpected results from a SQL query.
Table data:
users:
id username
1 admin
2 x1
3 y1
4 z1
my_connections:
id user_id friend_user_id status
1 1 2 201
2 2 1 201
3 2 4 201
4 1 3 200
5 2 3 201
6 3 2 201
7 4 2 201
8 4 1 200
jobs:
id user_id company_name designation from_date to_date
1 1 A 1 2011-06-01 2011-07-30
2 1 B 11 2011-08-02 2014-01-20
3 2 c 12 2012-05-02 2014-01-20
4 3 D 13 2010-05-02 2014-01-20
5 4 E 11 2009-05-25 2014-01-01
Here is my query:
SELECT users.id,users.username,my_connections.user_id,my_connections.friend_user_id,my_connections.status,jobs.user_id,jobs.company_name,
jobs.designation,jobs.from_date,MAX(jobs.to_date)
FROM users
LEFT JOIN jobs ON jobs.user_id = users.id
LEFT JOIN my_connections ON my_connections.friend_user_id = users.id
WHERE my_connections.status = 201 AND users.id IN (1,3,4)
GROUP BY jobs.company_name
ORDER BY jobs.to_date DESC
And the results:
id username user_id friend_user_id status user_id company_name designs from_date to_date
3 .. 2 3 201 3 D .. 2010-05-02 2014-01-20
4 .. 2 4 201 4 E .. 2009-05-25 2014-01-01
1 .. 2 1 201 1 A .. 2011-08-02 2014-01-20
1 .. 2 1 201 1 B .. 2011-06-01 2011-07-30
In the result, I wanted one row per friend_user_id, with the maximum value of to_date. Instead I am getting multiple rows (if there are multiple rows in the jobs table).
How can I fix this query?
if you want unique results on the friend_user_id field you must group by friend_user_id. This will guarantee unique results on the friend_user_id column. But im pretty sure you don't want that because it may show incorrect data. I am still unsure how the query is working because the group by only contains one field. You must group by all the raw fields in the select query and perform aggregate functions on fields that are not in the group by clause for example:
SELECT users.id,users.username,my_connections.user_id,my_connections.friend_user_id,my_connections.status,jobs.user_id,jobs.company_name,
jobs.designation,jobs.from_date,MAX(jobs.to_date)
FROM users
LEFT JOIN jobs ON jobs.user_id = users.id
LEFT JOIN my_connections ON my_connections.friend_user_id = users.id
WHERE my_connections.status = 201 AND users.id IN (1,3,4)
GROUP BY users.id,users.username,my_connections.user_id,my_connections.friend_user_id,my_connections.status,jobs.user_id,jobs.company_name,
jobs.designation,jobs.from_date
ORDER BY jobs.to_date DESC
In this query all of the fields in the group by clause are in the select clause. Now all the fields not included in the group by clause can use functions like: MAX(), AVG(), SUM() etc.