select all columns from both tables postgresql function - sql

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.

Related

I need to create a VIEW from an existing TABLE and MAP an additional COLUMN to that VIEW

I am fairly new to SQL. What I am trying to do is create a view from an existing table. I also need to add a new column to the view which maps to the values of an existing column in the table.
So within the view, if the value in a field for Col_1 = A, then the value in the corresponding row for New_Col = C etc
Does this even make sense? Would I use the CASE clause? Is mapping in this way even possible?
Thanks
The best way to do this is to create a mapping or lookup table
For example consider the following LOOKUP table.
COL_A NEW_VALUE
---- -----
A C
B D
Then you can have a query like this:
SELECT A.*, LOOK.NEW_VALUE
FROM TABLEA AS A
JOIN LOOKUP AS LOOK ON A.COL_A = LOOK.COL_A
This is what DimaSUN is doing in his query too -- but in his case he is creating the table dynamically in the body of the query.
Also note, I'm using a JOIN (which is an inner join) so only results in the lookup table will be returned. This could filter the results. A LEFT JOIN there would return all data from A but some of the new columns might be null.
Generally, a view is an instance of a table/a replica provided that there is no alteration to the original table. So, as per your query you can manipulate the data and columns in a view by using case.
Create View viewname as
Select *,
case when column=a.value then 'C'
....
ELSE
END
FROM ( Select * from table) a
If You have restricted list of replaced values You may hardcode that list in query
select T.*,map.New_Col
from ExistingTable T
left join (
values
('A','C')
,('B','D')
) map (Col_1,New_Col) on map.Col_1 = T.Col_1
In this sample You hardcode 'A' -> 'C' and 'B' -> 'D'
In general case You better may to use additional table ( see Hogan answer )

Postgres SQL: Find exceptions when using an in clause

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

Do something with each row and then get union of results - SQL (DB2)

I couldn't find solution for this problem.
I have table A with primary key ROW_ID, table B with same extern key and column SOMETHING.
Also, I have function created like this:
CREATE FUNCTION FIND_SOMETHING_FOR_ID(ROW_ID INTEGER)
RETURNS TABLE(SOMETHING INTEGER)
BEGIN ATOMIC
RETURN
SELECT SOME_SCALAR_FUNCTION(SOMETHING)
FROM B b
WHERE b.ROW_ID=ROW_ID;
END#
The thing I want to do is: for each ROW_ID in A get table returned by FIND_SOMETHING_FOR_ID
and then get UNION of all tables.
According to the documentation, you can do what you want as:
select fsfi.*
from A a cross join
table(find_something_for_id(a.row_id)) fsfi;
That is, a table-valued function can reference tables before it in the from clause, but not after it. (Note: I replaced the , in the from with cross join because I abhor commas in the from clause.)
By the way, SQL Server solves this problem with the cross apply operator.

SQL statement to return data from a table in an other sight

How would the SQL statement look like to return the bottom result from the upper table?
The last letter from the key should be removed. It stands for the language. EXP column should be split into 5 columns with the language prefix and the right value.
I'm weak at writing more or less difficult SQL statements so any help would be appreciated!
The Microsoft Access equivalent of a PIVOT in SQL Server is known as a CROSSTAB. The following query will work for Microsoft Access 2010.
TRANSFORM First(table1.Exp) AS FirstOfEXP
SELECT Left([KEY],Len([KEY])-2) AS [XKEY]
FROM table1
GROUP BY Left([KEY],Len([KEY])-2)
PIVOT Right([KEY],1);
Access will throw a circular field reference error if you try to name the row heading with KEY since that is also the name of the original table field that you are deriving it from. If you do not want XKEY as the field name, then you would need to break apart the above query into two separate queries as shown below:
qsel_table1:
SELECT Left([KEY],Len([KEY])-2) AS XKEY
, Right([KEY],1) AS [Language]
, Table1.Exp
FROM Table1
ORDER BY Left([KEY],Len([KEY])-2), Right([KEY],1);
qsel_table1_Crosstab:
TRANSFORM First(qsel_table1.Exp) AS FirstOfEXP
SELECT qsel_table1.XKEY AS [KEY]
FROM qsel_table1
GROUP BY qsel_table1.XKEY
PIVOT qsel_table1.Language;
In order to always output all language columns regardless of whether there is a value or not, you need to spike of those values into a separate table. That table will then supply the row and column values for the crosstab and the original table will supply the value expression. Using the two query solution above we would instead need to do the following:
table2:
This is a new table with a BASE_KEY TEXT*255 column and a LANG TEXT*1 column. Together these two columns will define the primary key. Populate this table with the following rows:
"AbstractItemNumberReportController.SelectPositionen", "D"
"AbstractItemNumberReportController.SelectPositionen", "E"
"AbstractItemNumberReportController.SelectPositionen", "F"
"AbstractItemNumberReportController.SelectPositionen", "I"
"AbstractItemNumberReportController.SelectPositionen", "X"
qsel_table1:
This query remains unchanged.
qsel_table1_crosstab:
The new table2 is added to this query with an outer join with the original table1. The outer join will allow all rows to be returned from table2 regardless of whether there is a matching row in the table1. Table2 now supplies the values for the row and column headings.
TRANSFORM First(qsel_table1.Exp) AS FirstOfEXP
SELECT Table2.Base_KEY AS [KEY]
FROM Table2 LEFT JOIN qsel_table1 ON (Table2.BASE_KEY = qsel_table1.XKEY)
AND (Table2.LANG = qsel_table1.Language)
GROUP BY Table2.Base_KEY
PIVOT Table2.LANG;
Try something like this:
select *
from
(
select 'abcd' as [key], right([key], 1) as id, expression
from table1
) x
pivot
(
max(expression)
for id in ([D], [E])
) p
Demo Fiddle

How to access columns on a cursor which is a join on all elements of two tables in Oracle PL/SQL

I am trying to run a cursor on full join of two tables but having problem accessing the columns in cursor.
CREATE TABLE APPLE(
MY_ID VARCHAR(2) NOT NULL,
A_TIMESTAMP TIMESTAMP,
A_NAME VARCHAR(10)
);
CREATE TABLE BANANA(
MY_ID VARCHAR(2) NOT NULL,
B_TIMESTAMP TIMESTAMP,
B_NAME VARCHAR(10)
);
I have written a Full join to return all related rows from tables A and B where any of the two timestamps are in future.
i.e. if a row in table APPLE has timestamp in future then fetch row from APPLE joined with row from BANANA on MY_ID
Similarly, if a row in table BANANA has timestamp in future then fetch row from BANANA joined with row from APPLE on MY_ID
This full join works for me.
select * from APPLE a full join BANANA b on a.MY_ID = b.MY_ID where
(
a.A_TIMESTAMP > current_timestamp
or b.B_TIMESTAMP > current_timestamp
);
Now I want to iterate over each joined record and do some processing. I am able to access the columns which are only present in one tables but getting error when trying to access the column names which are same in both tables. For ex. ID in this case.
create or replace
PROCEDURE testProc(someDate IN DATE)
AS
CURSOR c1 IS
select * from APPLE a full join BANANA b on a.MY_ID = b.MY_ID where
(
a.A_TIMESTAMP > current_timestamp
or b.B_TIMESTAMP > current_timestamp
);
BEGIN
FOR rec IN c1
LOOP
DBMS_OUTPUT.PUT_LINE(rec.A_NAME);
DBMS_OUTPUT.PUT_LINE(rec.A_TIMESTAMP);
DBMS_OUTPUT.PUT_LINE(rec.MY_ID);
END LOOP;
END testProc;
I get this error when I compile the above proc:
Error(16,28): PLS-00302: component 'MY_ID' must be declared
and I am not sure how would I access the MY_ID element. I am sure it will be pretty
straight forward but I am new to database programming and have been trying but unable to find the right way to do it.
Any help is appreciated.
Thanks
One other thing you can do in this case is to join the tables with the USING clause instead of using ON, as in:
select *
from APPLE a
full join BANANA b
USING (MY_ID)
where a.A_TIMESTAMP > current_timestamp or
b.B_TIMESTAMP > current_timestamp
USING can be used if the columns on both tables have the same name, and the comparison of the key values is made using the equality ('=') operator. In the result set there will be one column named MY_ID along with the other columns from both table (A_TIMESTAMP, B_TIMESTAMP, etc).
Share and enjoy.
I assume the problem is that MY_ID is defined in both tables, so * gets both of them. Try defining the cursor using this query:
select coalesce(A.MY_ID, B.MY_ID) as MY_ID,
A_TIMESTAMP, A_NAME, B_TIMESTAMP, B_NAME
from APPLE a full join
BANANA b
on a.MY_ID = b.MY_ID
where a.A_TIMESTAMP > current_timestamp or b.B_TIMESTAMP > current_timestamp;
EDIT:
You have two issues with conflicting columns. If this were just an inner join, you could do:
select A.*, B_TIMESTAMP, B_NAME
That is, you can select the columns from one table using * and the rest individually. However, this is a full outer join, so there is a set of columns where you want to use coalesce().
So, the best answer is that you should list out all the columns. This is good coding practice anyway, and helps protect the code from inadvertent mistakes when columns are added or removed from the table.