I have table which has many columns and I want to select just some of them - but I want to select columns which names are stored in another table(don't ask me why like this, I'm just trying to get something from existing system).
My table with data:
Table 1
id | username | age | height | hobby | weight | eye_color
1 | ... some users data...
2 | ... some users data...
3 | ... some users data...
And another table with column names from Table 1 which I want to select
Table 2
id | columnname
1 | username
2 | height
3 | weight
so after all sql should do something like this:
select
t.username,
t.height,
t.weight
from Table1 t
If I change something in Table 2 - then select sql also should be changed
How can I do it in PgSQL?
Related
I have the following table:
CREATE TABLE tree_node (
id serial primary key,
name character varying(255),
parent_id integer references tree (id)
);
The table contains many trees with up to about 1000 nodes.
(I'm able to query a tree and its descendants efficiently with a recursive query).
However, I need to be able to copy a single tree in one operation. Say I have a tree with 3 nodes, ids 1,2,3 (this is potentially a large tree). I would like to make a copy of it i.e. creating new nodes with new ids. (Here the copied tree is ids 4,5,6):
id | name | parent_id
----+-----------------+-----------
1 | NodeA |
2 | NodeA.1 | 1
3 | NodeA.1.1 | 2
4 | NodeA(copy) |
5 | NodeA.1(copy) | 4
6 | NodeA.1.1(copy) | 5
Is there a way to copy a tree and its descendants more efficiently than inserting each tree node separately (because the new parent_id is needed)?
There you go:
\i tmp.sql
CREATE TABLE tree_node (
id serial primary key
, name varchar
, parent_id integer references tree_node (id)
);
INSERT INTO tree_node(name, parent_id) VALUES
( 'Node-A', NULL)
, ( 'Node-A.1', 1)
, ( 'Node-A.1.1', 2)
;
SELECT * FROM tree_node;
-- Find the top value of the sequence
-- and use it as an increment on all the copies
WITH top(val) AS
(select currval('tree_node_id_seq')
)
INSERT INTO tree_node(id, name, parent_id)
SELECT id+top.val
, name|| '(copy)'
, parent_id + top.val
FROM tree_node
CROSS JOIN top
;
SELECT * FROM tree_node;
-- bump the sequence
WITH nxt AS (
select max(id) mx from tree_node
)
SELECT setval('tree_node_id_seq', (select mx FROM nxt) )
;
Output:
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 3
id | name | parent_id
----+------------+-----------
1 | Node-A |
2 | Node-A.1 | 1
3 | Node-A.1.1 | 2
(3 rows)
INSERT 0 3
id | name | parent_id
----+------------------+-----------
1 | Node-A |
2 | Node-A.1 | 1
3 | Node-A.1.1 | 2
4 | Node-A(copy) |
5 | Node-A.1(copy) | 4
6 | Node-A.1.1(copy) | 5
(6 rows)
setval
--------
6
(1 row)
I am trying to create a manual table based off of a currently built views table.
The structure of this current table is as follows:
ID | Column1 | Column2 | Buffer Days
1 | Asdf | Asdf1 | 91
2 | Qwert | Qwert1 | 11
3 | Zxcv | Zxcv1 | 28
The goal is to add a 4th column after Buffer Days that lists the sys date + the number in buffer days
So the outcome would look like:
ID | Column1 | Column2 | Buffer Days | Lookout Date
1 | Asdf | Asdf1 | 91 | 02-Jan-18
That requirement smells like a virtual column candidate. However, it won't work:
SQL> create table test
2 (id number,
3 column1 varchar2(10),
4 buffer_days number,
5 --
6 lookout_date as (SYSDATE + buffer_days) --> virtual column
7 );
lookout_date as (SYSDATE + buffer_days)
*
ERROR at line 6:
ORA-54002: only pure functions can be specified in a virtual column expression
Obviously, as SYSDATE is a non-deterministic function (doesn't return the same value when invoked).
Why not an "ordinary" column in existing table? Because you shouldn't store values that are calculated using other table columns anyway. For example, good old Scott's EMP table contains SAL and COMM columns. It doesn't (and shouldn't) contain TOTAL_SAL column (as SAL + COMM) because - when SAL and/or COMM changes, you have to remember to update TOTAL as well.
Therefore, a view is what could help here. For example:
SQL> create table test
2 (id number,
3 column1 varchar2(10),
4 buffer_days number
5 );
Table created.
SQL> create or replace view v_test as
2 select id,
3 column1,
4 buffer_days,
5 sysdate + buffer_days lookout_date
6 from test;
View created.
SQL> insert into test (id, column1, buffer_days) values (1, 'asdf', 5);
1 row created.
SQL> select sysdate, v.* from v_test v;
SYSDATE ID COLUMN1 BUFFER_DAYS LOOKOUT_DA
---------- ---------- ---------- ----------- ----------
23.12.2017 1 asdf 5 28.12.2017
SQL>
I have a table containing, for example, this data:
id | value | name | date
1 | 1 | 'one' | 2015-01-02
2 | 1 | 'two' | 2015-02-03
3 | 2 | 'three'| 2014-01-03
4 | 2 | 'four' | 2014-01-02
I want for each distinct value, the name of the row with the latest date. So:
value | name | date
1 | 'two' | 2015-02-03
2 | 'three'| 2014-01-03
I currently have this query: SELECT value, MAX(date) FROM table GROUP BY value, which gives me the value and date columns I'm looking for. How do I modify the query to add the name field? Simply adding it to the SELECT clause won't work, as Postgres will (understandably) complain I have to add it to the GROUP BY clause. But doing so will add it to the uniqueness check, and my query will return all 4 rows. All I need is the name of the row where it found the latest date.
distinct on() is the most efficient way to do this with Postgres
select distinct on (value) id, value, name, date
from the_table
order by value, date;
SQLFiddle example: http://sqlfiddle.com/#!15/dff68/1
This will give you all required fields:
select t1.* from table t1
inner join (
SELECT value, MAX(date) as date FROM table GROUP BY value
)t2 on t1.date=t2.date;
SQL Fiddle: http://sqlfiddle.com/#!15/9491f/2
I have following table:
CREATE TABLE Kundendaten (
beschreiben_knr INTEGER REFERENCES Kunde(knr) DEFERRABLE INITIALLY DEFERRED,
erstelldatum DATE,
anschrift VARCHAR(40),
sonderrabat INTEGER,
PRIMARY KEY (erstelldatum, beschreiben_knr)
);
If i make this query:
select * from Kundendaten ORDER BY erstelldatum DESC;
i get:
beschreiben_knr | erstelldatum | anschrift | sonderrabat
-----------------+--------------+---------------+-------------
1 | 2015-11-01 | Winkelgasse 5 | 0
2 | 2015-11-01 | Badeteich 7 | 10
3 | 2015-11-01 | Senfgasse 7 | 15
1 | 2015-10-30 | Sonnenweg 3 | 5
But i need to get only the entry for the highest date entry if there are more then one. In this case the last row should not appear.
How can i achieve this in postgresql?
You want something like WHERE erstelldatum = MAX(DATE) but that doesn't work. You can use a sub-query to get the newest date.
SELECT *
FROM Kundendaten
WHERE erstelldatum = (
SELECT MAX(erstelldatum) FROM Kundendaten
);
(SQL Fiddle)
Postgres will optimize that subquery so it is only run once, but you'll want to make sure erstelldatum is indexed.
I have got a SQL-Table were eache line consists a singel Value of some kind of Virtuel-Tabel - means the real existig SQL-Table looks like this:
-----------------------------------------
|DataRecordset | DataField | DataValue |
-----------------------------------------
| 1 | Firstname | John |
| 1 | Lastname | Smith |
| 1 | Birthday | 18.12.1963 |
| 2 | Firstname | Jane |
| 2 | Lastname | Smith |
| 2 | Birthday | 14.06.1975 |
-----------------------------------------
and I need to get something that feels like this:
-------------------------------------
| Firstname | Lastname | Birthday |
-------------------------------------
| John | Smith | 18.12.1963 |
| Jane | Smith | 14.06.1975 |
-------------------------------------
the reason why the real existing SQL-Table is stored like the first one is, that there are a lot more information around the core-data... like who write the data... when was the data written... from which to which time was the data significant... so there are a lot of diffrent variabels which decides which line from the first table i use to generate the second one.
I created a User-Defined-Tabletype on the SQL-Server which looks like the second table.
Then i start writing a procedure...
DECLARE #secondTable secondTable_Typ
DECLARE firstTable_Cursor CURSOR FOR SELECT DataRecordset, ... WHERE...lot of Text
OPEN firstTable_Cursor
FETCH NEXT FROM firstTable_Cursor
INTO #DataRecordset, #...
WHILE ##FETCH_STATUS = 0
BEGIN
IF NOT EXISTS(SELECT * FROM #secondTable WHERE DataRecordset= #DataRecordset)
BEGIN
the Problem i have... now i need some kind of dynamic Query, because i want do something like this:
INSERT INTO #secondTable (DataRecordset, #DataField ) VALUES (#DataRecordset, #DataValue)
but i cant use the variable #DataField like this... so i used google and found the function sp_executesql... i wrote the following code:
SET #sqlString = 'INSERT INTO #xsecondTable (DataRecordset, ' + #DataField + ') VALUES (#xDataRecordset, #xDataValue)'
EXEC sp_executesql #sqlString, N'#xsecondTable secondTable_Typ, #xDataRecordset smallint, #xDataValue sql_variant', #secondTable , #DataRecordset, #DataValue
but when i run the procedure i got an error that means i have to add a parameter "READONLY" to "#xsecondTable"...
i think the problem is, that sp_executesql can use variables as input or as outup... but i am not shure if its possiple to get this user defined table type into this procedure...
someone any idea how to get this code to run?
thank you very much
Have you considered doing a PIVOT on the data? Something along the lines of:
SELECT
[Firstname]
, [Lastname]
, [Birthday]
FROM
(
SELECT
[DataRecordset]
, [DataField]
, [DataValue]
FROM [Table]
) DATA
PIVOT
(
MIN ([DataValue]) FOR [DataField] IN
(
[Firstname]
, [Lastname]
, [Birthday]
)
) PVT