How to count by two fields and join with other table Postgres? - sql

I have two tables, one table user and second table transactions related with the transactions done by a user. I want to do a query that give me the count by name and date, with the fields in user table. How can I do it?
Table user:
Name Id Card
-----------------
Alex 01 N
James 02 Y
Table transaction:
Name Date
-----------------
Alex 01/07/2012
Alex 01/12/2012
James 01/08/2012
Alex 01/07/2012
Alex 01/12/2012
James 01/07/2012
James 01/07/2012
I want sometihng like this:
Name Date Transactions ID Card
---------------------------------------------
Alex 01/07/2012 2 01 N
Alex 01/12/2012 2 01 N
James 01/08/2012 1 02 Y
James 01/07/2012 2 02 Y
First of all I tryed to count by two columns with something like this:
select name, date, count(name, date) from pm_transaction GROUP BY (name,date)
select count(distinct(machine, date)) from pm_transaction
But it does not work, I tried a lot of combinations but no one works

Try this
select tb1.name, tb2.date , tb2.transaction , tb1.Id, tb1.card
from tbUser as tb1
inner join
(select date,
name,
count(date) as transaction
from tbTransaction group by date)
as tb2 on tb1.name = tb2.name

This looks like simple aggregation task. Just check and correct table join condition and table names:
select u.name, t.date, count(1) as transactions, u.id, u.card
from transaction t
join user_table u on u.name = t.name
group by u.name, t.date, u.id, u.card;

Related

Oracle select from table and join where date is oldest

My real life problem is more comlpex, but the issue can be washed down to the following: I have one table with clients, and another table with clients' bank accounts. Now I want to do a select returning all clients that have bank accounts, joining with the bank account that was used least recently, ordered by the BANK_ID.
CLIENT:
CLIENT_ID NAME
-----------------
1 JOE
2 BEN
3 SUE
BANK_ACCOUNT:
BANK_ID CLIENT_ID LAST_USED
-----------------------------------
1 2 Jan 1 2020
2 1 Mar 15 2020
3 2 Aug 5 2020
4 1 Feb 7 2020
5 1 Oct 13 2020
So Joe has three bank accounts, Ben has two, and Sue does not have any.
The select should contain only Joe and Ben. Ben should go first because his "oldest" bank account is on BANK_ID 1 while Joe's is on BANK_ID 4.
BANK_ID CLIENT_ID NAME
---------------------------
1 2 BEN
4 1 JOE
I've been playing around with joins and subqueries, but I'm not sure what would be the best way to accomplish this query.
Thank you
A typical method is to use row_number():
select ba.bank_id, ba.client_id, c.name
from client c join
(select ba.*,
row_number() over (partition by client_id order by last_used) as seqnum
from bank_account ba
) ba
on ba.client_id = c.client_id and ba.seqnum = 1
order by ba.bank_id;
In Oracle, you can also use aggregation:
select max(ba.bank_id) keep (dense_rank over order by ba.last_used) as bank_id,
ba.client_id, c.name
from bank_account ba
on ba.client_id = c.client_id
group by ba.client_id, c.name
order by ba.bank_id;
One option uses a lateral join:
select ba.bank_id, ba.client_id, c.name
from client c
cross apply (
select ba.*
from bank_account ba
where ba.client_id = c.client_id
order by ba.last_used
fetch first row only
) ba
The upside is that you can easily bring more columns from the bank account tables (say you want the last_used date for example), by just expanding the select clause.

PostgreSQL: How to join two tables using between date?

I really don't know how to ask this question of mine.
I'll illustrate it using two tables I needed to join.
TABLE_1
Name Date
John 01-01-2016
May 04-08-2015
Rose 10-25-2016
Mary 12-15-2015
Ruby 07-07-2017
TABLE_2
Signatory DateFrom DateTo
President 1 01-01-2015 12-31-2015
President 2 01-01-2016 12-31-2016
RESULT:
Name Date Signatory
John 01-01-2016 President 2
May 04-08-2015 President 1
Rose 10-25-2016 President 2
Mary 12-15-2015 President 1
Ruby 07-07-2017 NULL
All I need to check if the Date of Table_1 is within the DateFrom and DateTo of Table_2 to get the Signatory field.
How I can do that?
Thanks a lot! ^_^
Try this:
SELECT t1.*, t2.Signatory
FROM Table_1 AS t1
LEFT JOIN Table_2 AS t2
ON t1."Date" BETWEEN t2.DateFrom AND t2.DateTo
What you need is just a LEFT JOIN with BETWEEN in the ON clause in order to determine whether Date field of Table_1 falls within any [DateFrom, DateTo] interval of Table_2.
Demo here

Create view by joining three tables in SQL

I have three tables STUDENTS, SUBJECTS, RANK ,with data as -
1) STUDENTS [NAME(Primary)]
NAME
--------
Alex
Greg
2) SUBJECTS [ID(Primary)]:
ID
--------
100
101
102
3) RANK [SEQ(Primary), NAME, ID, RANK]
SEQ NAME ID RANK
------ ------- ------ ------
1 Alex 100 A
2 Greg 100 A
3 Greg 101 B
I want to create a view that should display data as
NAME ID RANK
------- ------ ------
Alex 100 A
Alex 101 Z
Alex 102 Z
Greg 100 A
Greg 101 B
Greg 102 Z
So, for every student and for every subject, the View should display the RANK if present in RANK table, else replace the NULL with 'Z'.
I'm a newbie to SQL. So any help in forming the query would be deeply appreciated!
cross join student and subject then left outer join the result with rank to get ranks for all (student, subject) combination. selecting column with NVL OR COALESCE will replace NULL with 'z'.
SELECT st.name,
su.id,
NVL(ra.rank,'Z') Rank, --COALESCE(ra.rank,'Z') Rank
FROM student st
CROSS JOIN subject su
LEFT OUTER JOIN rank ra
ON ra.name = st.name
AND ra.id = su.id
ORDER BY st.name,su.id
Note : ORDER BY can be removed from above query if you don't need.
fiddle
SELECT r.NAME, r.ID, NVL(r.RANK, 'Z')
FROM RANK r, studendts st, SUBJECTS su
WHERE st. NAME = r. NAME
AND su.ID = r.ID
ORDER BY 1,2,3

ORA-01427: single-row subquery returns more than one row error

I have 2 tables (USERS and ACCOUNTS) with the following data in them:
USERS
UserID Name Account_Number
10 John Smith 13
20 Alex Brown 14
30 Mary Wade 34
ACCOUNTS
Account number Amount
13 40
34 30
14 30
13 60
14 10
I would like to know how I can write a query to return the following results:
UserID Name Total amount
13 John Smith 100
14 Alex Brown 40
34 Mary Wade 30
The query that I have tried is:
SELECT USER_ID, NAME, (SELECT SUM(AMOUNT) FROM ACCOUNTS GROUP BY ACCOUNT) AS TOTAL_AMOUNT
FROM USERS
JOIN ACCOUNTS
USING(ACCOUNT_NUMBER)
ORDER BY TOTAL_AMOUNT DESC;
When I execute this I get the following error: ORA-01427: single-row subquery returns more than one row.
Does anyone know how I might be able to modify the query so that it works as intended?
Thanks!
Please try:
select
Account_Number,
Name,
(select SUM(Amount) from ACOUNTS b where b.[Account number]=a.Account_Number) Total
from USERS a
order by Account_Number
Maybe something like this:
SELECT
USERS.USER_ID,
USERS.NAME,
SUM(ACCOUNTS.Amount) AS TotalAmout
FROM USERS
JOIN ACCOUNTS
ON ACCOUNTS.Account_number=USERS.Account_number
GROUP BY
USERS.USER_ID,
USERS.NAME
ORDER BY
TotalAmout DESC
Remove your subquery.. It is returning more than one row..
SELECT U.USERID, U.NAME, SUM(A.AMOUNT) AS TOTAL_AMOUNT
FROM USERS U
INNER JOIN ACCOUNT A on U.ACCOUNT_NUMBER=A.ACCOUNT_NUMBER
GROUP BY A.ACCOUNT_NUMBER,U.USERID, U.NAME
ORDER BY SUM(A.AMOUNT) DESC;
Fiddle

SQL: select three rows for each distinct value

For each distinct Name, I want to select the first three rows with the earliest time_stamp (or smallest number in UNIXTIME). What is the correct query?
Start Table:
Name Log-in Time
-------- -----------------
Don 05:30:00
Don 05:35:32
Don 07:12:43
Don 09:52:23
Don 05:32:43
James 03:30:00
James 03:54:23
James 09:51:54
James 14:43:34
James 43:22:11
James 59:43:33
James 20:12:11
Mindy 05:32:22
Mindy 15:14:44
Caroline 10:02:22
Rebecca 20:43:32
End Table:
Name Log-in Time
-------- -----------------
Don 05:30:00
Don 05:35:32
Don 07:12:43
James 03:30:00
James 03:54:23
James 09:51:54
Mindy 05:32:22
Mindy 15:14:44
Caroline 10:02:22
Rebecca 20:43:32
WITH Table (Name, LoginTime, Row) AS
(
SELECT
Name,
LoginTime,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY LoginTime)
FROM SomeTable
)
SELECT
Name,
LoginTime
FROM Table
WHERE
Row <= 3
An ansi standard approach actually looks to work with the following:
http://www.sqlfiddle.com/#!2/b814d/15
SELECT
NAME
, LOGIN
FROM (
SELECT
test_first.NAME,
test_first.LOGIN,
COUNT(*) CNT
FROM
TABLE_NAME test_first
LEFT OUTER JOIN
TABLE_NAME test_second
ON (test_first.NAME = test_second.NAME)
WHERE
test_first.LOGIN <= test_second.LOGIN
GROUP BY
test_first.NAME, test_first.LOGIN) test_order
WHERE
test_order.CNT <= 3
ORDER BY
NAME ASC, LOGIN ASC