How to select row from table but if it doesn't exist in that table, select from different table? - postgresql

This may be a really simple problem that I'm over-looking but i have this query:
SELECT is_accountant from users where customer_id='cus_4znUZe3lAy26FT'
(the customer id will vary, I'm using a node js script to grab a bunch of different customer ids to find out if they're accountants or not)
If there is no result, I want to search in a table called deleted_users for the same customer id ie:
SELECT is_accountant from deleted_users where customer_id='cus_4znUZe3lAy26FT'
Is there a way to do this within Postgresql?

SELECT coalesce(u.is_accountant, d.is_accountant)
from deleted_users d
full outer join users u on u.id = d.id
where 'cus_4znUZe3lAy26FT' in (d.customer_id, u.customer_id)

SELECT is_accountant from users where customer_id='cus_4znUZe3lAy26FT'
union all
SELECT is_accountant from deleted_users where customer_id='cus_4znUZe3lAy26FT'
and not exists
(SELECT is_accountant from users where customer_id='cus_4znUZe3lAy26FT')
or, as you are interested to know if user "is (or was)" accountant:
(does it matter in which table the user is? Agree?)
SELECT is_accountant from users where customer_id='cus_4znUZe3lAy26FT'
union
SELECT is_accountant from deleted_users where customer_id='cus_4znUZe3lAy26FT'

Related

Table with list of database administrators in IBM i

I want a list of users on an IBMi Machine who have access to create RCAC permissions (Create Mask, Row permission etc). Is this data stored in any table?
Not just in one table but I think this is a good start to list users with administative authority
SELECT
distinct AUTHORIZATION_NAME
FROM QSYS2.USER_INFO cross
join lateral (select * from table(systools.split(SPECIAL_AUTHORITIES,' '))) a
where element in ('*SECADM','*ALLOBJ')
union
SELECT
user_name
FROM qsys2.function_usage
where function_id = 'QIBM_DB_SECADM'
and usage = 'ALLOWED'

How to make a query with the data of another query on SQL?

I have a user table and another order table. A user can have many orders. How do I get the last 1000 users and those users use my last 1000 orders for each one?
Query - Get users
select distinct users.id, users.first_name, users.last_name
from users
limit 2;
Query - Get orders
select distinct orders.id, orders.user_id
from orders
limit 2;
First you need to know.. When it comes to query data don't do separate operation.. If you put out All Users and Orders Your data will be unordered and not consistency.. So you need to make Join to see All User with Order they have.. And as stated by #Sharon you need to add column date_ordered to see that order make.. I am assume you already have that column but i will call that column with date_ordered..
And your query will be :
select
users.id,
users.first_name,
users.last_name,
orders.id
from
users
inner join orders on users.id = orders.user_id
order by
orders.date_ordered desc
limit 1000
By order date_ordered use desc you will get the latest all the user with their order.. And i assume user_id column in table orders have constraint foreign key references to table users with column id..

Optimizing query to grab results from two tables

Lets say I have a db table called Document that contains rows for all the documents I own. I have another db table called Shared that has records for all documents (owned by other people) that I can read/write to.
Document
id
type
user_id
permissions
Shared
id
document_id
used_id
permissions
I was trying to write a query that would get me back all documents that I (given a user_id) own and have access to. My attempt is something like this:
Select id, type, user_id, permissions from Document where user_id = 123
union all
Select id, type, user_id, permissions from Document where id in
(select document_id from shared where user_id = 123)
The above seems a little bit verbose so I was wondering if there was a more succinct/efficient way to write the above (if it works at all)
Try using left join + where clause
Select d.id, d.type, d.user_id, d.permissions from Document d
left join shared s on s.document_id = d.id
and s.user_id = d.user_id
where d.user_id = 123
and s.document_id IS NOT NULL

Inner join with count and group by

I have 2 tables
Timetable :
pupil_id, staff_id, subject, lesson_id
Staff_info :
staff_id, surname
The timetable table contains 1000s of rows because each student's ID is listed under each period they do.
I want to list all the teacher's names, and the number of lessons they do (count). So I have to do SELECT with DISTINCT.
SELECT DISTINCT TIMETABLE.STAFF_ID,
COUNT(TIMETABLE.LESSON_ID),
STAFF.SURNAME
FROM STAFF
INNER JOIN TIMETABLE ON TIMETABLE.STAFF_ID = STAFF.STAFF_ID
GROUP BY TIMETABLE.STAFF_ID
However I get the error:
Column 'STAFF.SURNAME' is invalid in the select list because it is not
contained in either an aggregate function or the GROUP BY clause.
This should do what you want:
SELECT s.STAFF_ID, COUNT(tt.LESSON_ID),
s.SURNAME
FROM STAFF s INNER JOIN
TIMETABLE tt
ON tt.STAFF_ID = s.STAFF_ID
GROUP BY s.STAFF_ID, s.SURNAME;
Notes:
You don't need DISTINCT unless there are duplicates in either table. That seems unlikely with this data structure, but if a staff member could have two of the same lesson, you would use COUNT(DISTINCT tt.LESSON_ID).
Table aliases make the query easier to write and to read.
You should include STAFF.SURNAME in the GROUP BY as well as the id.
I have a preference for taking the STAFF_ID column from the table where it is the primary key.
If you wanted staff with no lessons, you would change the INNER JOIN to LEFT JOIN.
SELECT T.STAFF_ID,
T.CNT,
S.SURNAME
FROM STAFF S
JOIN (
SELECT STAFF_ID, CNT = COUNT(/*DISTINCT*/ LESSON_ID)
FROM TIMETABLE
GROUP BY STAFF_ID
) T ON T.STAFF_ID = S.STAFF_ID
Another option:
SELECT DISTINCT si.staff_id, surname, COUNT(lesson_id) OVER(PARTITION BY staff_Id)
FROM Staff_info si
INNER JOIN Timetable tt ON si.staff_id = tt.staff_id
When using Aggregate function(Count, Sum, Min, Max, Avg) in the Select column's list, any other columns that are in the Select column's list but not in a aggregate function, should be mentioned in GROUP BY section too. So you need to change your query as follow and add STAFF.SURNAME to GROUP BY section too:
SELECT TIMETABLE.STAFF_ID,
COUNT(TIMETABLE.LESSON_ID),
STAFF.SURNAME
FROM STAFF
INNER JOIN TIMETABLE ON TIMETABLE.STAFF_ID = STAFF.STAFF_ID
GROUP BY TIMETABLE.STAFF_ID,STAFF.SURNAME
Distinct is useless also in your scenario. and also as you are going to show the teachers name and Count lessons, you do not need to add TIMETABLE.STAFF_ID to Select's column's list,, but it should remain in Group By section to prevent duplicate names.
SELECT COUNT(TIMETABLE.LESSON_ID),
STAFF.SURNAME
FROM STAFF
INNER JOIN TIMETABLE ON TIMETABLE.STAFF_ID = STAFF.STAFF_ID
GROUP BY TIMETABLE.STAFF_ID,STAFF.SURNAME
You may need to take a look at this W3C post for more info

PostgreSQL: Select first row as column inside select

I got 2 tables like Customers and Orders, in table Customers I got columns id, name, in table Orders I got columns id, customer_id, order_date.
Now I need to make one select that will return me each Customer's id, name and the last order_date.
I tried to make like this:
select
Customers.id,
Customers.name,
(select Orders.order_date from Orders where Orders.customer_id = Customer.id order by order_date desc) as last_order_date
from
Customers
But it get the wrong index and takes forever to execute.
Whats the best way to make this select in PostgreSQL?
Thanks in advanced.
If not restricting by customer_id, then the query will end up having to scan the entire orders table.
SELECT c.id
,c.name
,MAX(o.order_date) AS last_order_date
FROM Customers c
LEFT OUTER JOIN Orders o ON (o.customer_id = c.id)
GROUP BY c.id, c.name