How to include and exclude ids in once query postgresql - postgresql

I use PostgreSQL 13.3
I'm trying to think how I can make include/exclude in query at the same time
I have include_system_ids [1,5] and exclude_system_ids [3]
There's one big table - records
system_records table
record
system_id
1
1
1
5
1
3
2
1
2
5
If a record contains an exclusive identifier, then it should not be included in the final selection. I had some several tries, but I didn't get a necessary result
Awaiting result: record with id 2
Fact result: 1, 2
My variants
select r.id from records r
left join (select record_id from system_records
where system_id in (1,5)
) include_ids on r.id = include_ids
left join (select record_id from system_records
where system_id not in (3)
) exclude_ids on r.id = exclude_ids.id
Honestly, I don't understand how I can do it((
Is there anyone who can help me

Maybe this query could be a solution (result here)
with x as (select record,string_agg(system_id::varchar,',') as sys_id from records group by record)
select records.*
from records,x
where records.record = x.record
and x.sys_id = '1,5'

Related

Inner join removed from the SQL query

I have a below SQL query to get the three records for notifying purpose.
SELECT orders.msg
FROM orders
INNER JOIN
(
SELECT id
FROM orders
WHERE type_id = 12
ORDER BY id DESC LIMIT 3 OFFSET 0
) AS items
ON orders.id = items.id;
When trying to make the query optimized, i made the changes as below.
SELECT orders.msg
FROM orders
WHERE type_id = 12
ORDER BY id DESC LIMIT 3 OFFSET 0;
Is the modified query seems to be OK or did i miss anything here or any other way of doing is there??
The simplified version on the bottom looks logically identical, to me, to the one on top:
SELECT msg
FROM orders
WHERE type_id = 12
ORDER BY id DESC LIMIT 3;
Note that the above query could benefit from the following index:
CREATE INDEX idx ON orders (type_id, id, msg);
This index would completely cover the WHERE, ORDER BY, and SELECT clauses.
You can try this also:
SELECT orders.msg
FROM orders
WHERE orders.id
IN (
SELECT id
FROM orders
WHERE type_id = 12
ORDER BY id
DESC LIMIT 3 OFFSET 0
)

How to make postgres (cursor?) start at particular row

I have created the following query:
select t.id, t.row_id, t.content, t.location, t.retweet_count, t.favorite_count, t.happened_at,
a.id, a.screen_name, a.name, a.description, a.followers_count, a.friends_count, a.statuses_count,
c.id, c.code, c.name,
t.parent_id
from tweets t
join accounts a on a.id = t.author_id
left outer join countries c on c.id = t.country_id
where t.row_id > %s
-- order by t.row_id
limit 100
Where %s is a number that starts at 0 and is incremented by 100 after each such query is conducted. I want to fetch all records from the database using this method, where I just increase the %s in the where condition. I found this approach on https://ivopereira.net/efficient-pagination-dont-use-offset-limit. I also included a column in my table which is corresponding to row number (I named it row_id). Now the problem is when I run this query the first time, it returns rows which have an row_id of 3 million. I would like the cursor (not sure if my terminology is correct) to start from rows with row_id 1 through 100 and so on. The table contains 7 million rows. Am I missing something obvious with which I could achieve my goal?

I want to get unique rows on joining tables

I am running the following query while trying to join 3 tables :
select
a.project_id, a.acc_name, a.project_name, a.iot,a.acc_id, a.active,
b.app_fte, b.contact_person, c.cost_call_date
from
Account a, Application b, account_version c
where
a.acc_id in (Select acc_id from account where acc_name='GGG') and
EXTRACT(MONTH FROM c.cost_call_date) = 3;
Sample data from the tables are as follows :
Account :
acc_id acc_name iot acc_contact project_id project_name ilc_code license_no active
2 GGG NA YYY 7777 HHH TTR 766 false
Application :
app_id app_name app_fte contact_person acc_id
1 sfsf 4 sdsdff 2
Account_version :
line_id acc_id version_no chargable_fte cost_call_date is_approved
9 2 7 4 2018-03-20
Here acc_id is the primary key for the Account table and the foreign key for the Application and Account_version tables. When I am running the above query I am getting 30 rows I have also tried using the distinct keyword but still I get 10 rows. Please help me in getting unique rows.
Try something like this
SELECT DISTINCT a.project_id, a.acc_name, a.project_name, a.iot,a.acc_id, a.active, b.app_fte, b.contact_person, c.cost_call_date
FROM Account a
INNER JOIN Application b
USING (acc_id)
INNER JOIN account_version c
USING (acc_id)
WHERE a.acc_name = 'GGG'
AND EXTRACT(MONTH FROM c.cost_call_date) = 3
For reference as to why your query was giving you more rows than expected, try running this:
SELECT a.*, b.*
FROM generate_series(1, 10) a, generate_series(1, 10) b
What you are doing by selecting from multiple tables as you did is a cross join. What you should actually be doing is an inner join to get the rows you want, and a DISTINCT if required to get only distinct rows from the results.

Subsetting records that contain multiple values in one column

In my postgres table, I have two columns of interest: id and name - my goal is to only keep records where id has more than one value in name. In other words, would like to keep all records of ids that have multiple values and where at least one of those values is B
UPDATE: I have tried adding WHERE EXISTS to the queries below but this does not work
The sample data would look like this:
> test
id name
1 1 A
2 2 A
3 3 A
4 4 A
5 5 A
6 6 A
7 7 A
8 2 B
9 1 B
10 2 B
and the output would look like this:
> output
id name
1 1 A
2 2 A
8 2 B
9 1 B
10 2 B
How would one write a query to select only these kinds records?
Based on your description you would seem to want:
select id, name
from (select t.*, min(name) over (partition by id) as min_name,
max(name) over (partition by id) as max_name
from t
) t
where min_name < max_name;
This can be done using EXISTS:
select id, name
from test t1
where exists (select *
from test t2
where t1.id = t2.id
and t1.name <> t2.name) -- this will select those with multiple names for the id
and exists (select *
from test t3
where t1.id = t3.id
and t3.name = 'B') -- this will select those with at least one b for that id
Those records where for their id more than one name shines up, right?
This could be formulated in "SQL" as follows:
select * from table t1
where id in (
select id
from table t2
group by id
having count(name) > 1)

Remove duplicate with separate column check TSQL

I have 2 tables having same columns and permission records in it.
One columns named IsAllow is available in both tables.
I am getting records of both tables in combine using UNION
But want to skip similar records if IsAllow = 0 in any one column - I don't want those records. But UNION returns all records and am getting confused.
Below are columns
IsAllow, UserId, FunctionActionId
I tried union but it gives both records. I want to exclude IsAllow = 0 in either table.
Sample data table 1
IsAllow UserId FunctionActionId
1 2 5
1 2 8
Sample data table 2
IsAllow UserId FunctionActionId
0 2 5 (should be excluded)
1 2 15
You can try this:
;with cte as(select *, row_number()
over(partition by UserId, FunctionActionId order by IsAllow desc) rn
from
(select * from table1
union all
select * from table2) t)
select * from cte where rn = 1 and IsAllow = 1
Version2:
select distinct coalesce(t1.UserId, t2.UserId) as UserId,
coalesce(t1.FunctionActionId, t2.FunctionActionId) as FunctionActionId,
1 as IsAllow
from tabl1 t1
full join table2 t2 on t1.UserId = t2.UserId and
t1.FunctionActionId = t2.FunctionActionId
where (t1.IsAllow = 1 and t2.IsAllow = 1) or
(t1.IsAllow = 1 and t2.IsAllow is null) or
(t1.IsAllow is null and t2.IsAllow = 1)