Postgres SQL: Find exceptions when using an in clause - sql

I am running the following (Postgres) SQL against a table containing a list of ids. The SQL below will return all the ids found in the list* below.
select id from table
where id in (1,2,3,5,8,11,13,22,34,55);
How can I return ids which are contained in the list but not in the table? I realise I can do this using a temp table (with the list in it) and a left outer join but is there a quicker/cleverer way?

To check if arbitrary ids exist in your table, use a CTE and exists
WITH ids (id) AS ( VALUES (1),(2),(3),(5),(8),(11),(13),(22),(34),(55)
)
SELECT id
FROM ids
WHERE NOT EXISTS(SELECT TRUE FROM table WHERE table.id = ids.id)
note1: alternatively use a left join instead of WHERE NOT EXISTS
note2: it may be necessary to add the appropriate type casts
Or you can use EXCEPT
WITH ids (id) AS ( VALUES (1),(2),(3),(5),(8),(11),(13),(22),(34),(55)
)
SELECT id
FROM ids
EXCEPT ALL
SELECT id FROM ids

Related

Find if a string is in or not in a database

I have a list of IDs
'ACE', 'ACD', 'IDs', 'IN','CD'
I also have a table similar to following structure
ID value
ACE 2
CED 3
ACD 4
IN 4
IN 4
I want a SQL query that returns a list of IDs that exists in the database and a list of IDs that does not in the database.
The return should be:
1.ACE, ACD, IN (exist)
2.IDs,CD (not exist)
my code is like this
select
ID,
value
from db
where ID is in ( 'ACE', 'ACD', 'IDs', 'IN','CD')
however, the return is 1) super slow with all kinds of IDs 2) return multiple rows with the same ID. Is there anyway using postgresql to return 1) unique ID 2) make the running faster?
Assuming no duplicates in table nor input, this query should do it:
SELECT t.id IS NOT NULL AS id_exists
, array_agg(ids.id)
FROM unnest(ARRAY['ACE','ACD','IDs','IN','CD']) ids(id)
LEFT JOIN tbl t USING (id)
GROUP BY 1;
Else, please define how to deal with duplicates on either side.
If the LEFT JOIN finds a matching row, the expression t.id IS NOT NULL is true. Else it's false. GROUP BY 1 groups by this expression (1st in the SELECT list), array_agg() forms arrays for each of the two groups.
Related:
Select rows which are not present in other table
Hmmm . . . Is this sufficient:
select ids.id,
(exists (select 1 from table t where t.id = ids.id)
from unnest(array['ACE', 'ACD', 'IDs', 'IN','CD']) ids(id);

select all columns from both tables postgresql function

i have a simple sql join query
SELECT a.*,b.*
FROM Orders a
JOIN Customers b ON a.CustomerID=b.CustomerID
which selects all columns from both tables . I need to achieve the same in
Postgresql function,but i am not able to select data from 2nd table
CREATE FUNCTION get_data (p_pattern VARCHAR,p_year INT)
RETURNS TABLE (
orders.*,Customers.*
)
AS $$
The one problem is that neither function nor views can return the columns with same names (in your example columns CustomerID presented in both tables). And the another one - syntax:
RETURNS TABLE ( column_name column_type [, ...] )
from the official doc, nothing about table_name.*.
Aside of the obvious solution where you specifying the complete list of columns, there is one trick with composite (row, record) types:
CREATE FUNCTION get_data (p_pattern VARCHAR,p_year INT)
RETURNS TABLE (order orders, customer customers)
AS $$
Note that you can use table/view names as types in declarations.
And in that case your query could looks like
SELECT a, b
FROM Orders a
JOIN Customers b ON a.CustomerID=b.CustomerID
After that the usage of the function would be:
select
*, -- two composite columns
(order).*, -- all columns from table orders
(customer).*, -- all columns from table customers
(order).CustomerID -- specific column from specific table
from
get_data(<parameters here>);
dbfiddle
Considering the columns are present on which you are joining, you can do this:
SELECT * FROM Orders a,Customers b WHERE a.CustomerID=b.CustomerID;
For more see the official docs: https://www.postgresql.org/docs/8.2/static/tutorial-join.html
You can also refer this: https://www.tutorialspoint.com/postgresql/postgresql_using_joins.htm
.It has good examples and references what joins are there in postgre and how to do them.

SQL Query to match if data is not present in another table

I have two tables named tblStockManagement and tblFolding in my database. i have column Name in tblFolding table and column FoldingID as Foreign Key in tblStockManagement table. now i have comboBox in my Winform and i want Names of Items in combobox from tblFolding Table but only those items that are not in tblStockManagement Table.
(because i dont want to select data again if it is already in tblStockManagement table . instead i will update the quantity later).
these are the screenshots of both of tables. please tell me how can i do that
NOT EXISTS version:
select *
from tblFolding f
where not exists (select * from tblStockManagement SM
where sm.FoldingID = f.FoldingID)
NOT EXISTS is "NULL safe", which NOT IN isn't.
This is you need.Basically a sub query which gets all folding id and using not in operator I exclude those matching sets.
SELECT Name
FROM tblFolding
WHERE FoldingID NOT IN (
SELECT FoldingID
FROM tblStockManagement
)
;
You can use SQL NOT condition
Select Name
From tblFolding
Where FoldingId Not In (Select FoldingId From tblStockManagement)
Order By Name

Subquery has too many columns

I have two tables with same structure: tmp_grn and grn.
I have to delete rows from table tmp_grn which already exists in table grn.
Problem is I don't have a unique or primary key but I can determine a unique row with the combination of two columns. Let's say column names are grn_code and item_skucode.
My query:
DELETE FROM tmp_grn
WHERE grn_code AND item_skucode IN
(SELECT grn_code , item_skucode FROM grn);
I am getting this error:
ERROR: subquery has too many columns
What should be the right way to do this?
If you want to combine two columns, you need to put them into parenthesis:
DELETE FROM tmp_grn
WHERE (grn_code, item_skucode) IN (SELECT grn_code, item_skucode
FROM grn);
But suslov's answer using an exists is most probably faster - you need to check the execution plan to verify that.
You can use exists (if you want to check the pair of values):
delete from tmp_grn t
where exists ( select *
from grn
where grn_code = t.grn_code
and item_skucode = t.item_skucode);
delete * from tmp_grn intersect select * from grn

SQL JOIN and COUNT COMMANDS

I have two different tables, we will call table 1 and table 2. Within table 1, I have a column known as featureid which is a numerical value that corresponds to a numerical value in table 2 known as the termid. Also, within this table 2, each of the different termid corresponds to a plain text description of that termid.
What I am attempting to do is join the featureid in table 1 to the termid in table 2, but have the output be a two column display of the plain text description and occurrence of each within table 1.
I know I need to use the JOIN and COUNT syntax within SQL, but not sure how to correctly write the command.
Thanks!
You actually only need one column in the GROUP BY. It's also good practice to specify which values are coming from which table, like so:
SELECT
table2.textDesc,
COUNT(table1.featureid) AS OccurrenceCount
FROM
table1
INNER JOIN
table2 ON
table1.featureid = table2.termid
GROUP BY table2.textDesc
I think this is what you are looking for:
SELECT textDesc, COUNT(featureid)
FROM table1, table2
WHERE featureid=termid
GROUP BY featureid, textDesc
Alternatively, you can use a different syntax (with the same end result) like so:
SELECT textDesc, COUNT(featureid)
FROM table1 INNER JOIN table2
ON featureid=termid
GROUP BY featureid, textDesc