Postgres Editable Union View - postgresql

I have a table which stores 'links' between 2 people. In order prevent further complications down the road on an application I am building, I want to create an editable view, that shows the link records and an inverse copy of the link records.
Meaning if Joe is linked to Sally, then the view should show Joe linked to Sally and Sally linked to Joe.
So I have created a UNION as follows:
CREATE VIEW links AS
SELECT id,
link_origin_id AS person_id,
link_origin_id,
link_rcvd_id,
link_type,
link_summary,
created_at,
updated_at
FROM links_data
UNION
SELECT id,
link_rcvd_id,
link_origin_id,
link_rcvd_id,
link_type,
link_summary,
created_at,
updated_at
FROM links_data
The view works fine. Note that the view creates an additional column 'person_id' which is not in the underlying table.
I am running into trouble creating postgres rules that will edit the underlying table.
Specifically, I can successfully edit a table view when it is not a UNION view. But below is what occurs when I try to write a rule with a UNION view:
CREATE RULE inverse_links AS ON INSERT TO links DO INSTEAD
INSERT INTO links_data
(id, link_origin_id, link_type, link_summary, link_rcvd_id, created_at,
updated_at)
VALUES (nextval('people_id_seq'), new.link_origin_id, new.link_type,
new.link_summary, new.link_rcvd_id, new.created_at, new.updated_at)
RETURNING *;
The above rule should redirect the edits to the underlying table 'links_data'.
But I am getting the following error:
ERROR: RETURNING list's entry 3 has different type from column "link_origin_id"
********** Error **********
ERROR: RETURNING list's entry 3 has different type from column "link_origin_id"
SQL state: 42P17
The 2 things I feel might be the problem is that 1) the view has an additional column which is causing the column types to not match up or 2) there might be something with the fact that the table is a UNION on itself and editing this might be a problem.
Any idea of where I can go with this?

Disclaimer: almost no experience with updatable views.
Your RETURNING clause is the problem - the links_data table most probably has 7 colums (as shown by your view definition and the ON INSERT rule) and you're returning their contents for the just inserted row with RETURNING * but your view has 8 columns. Check and sync those two lists.

Related

Automatic count of rows stored in a PostgreSQL field

I am creating 2 tables, one called quizes with:
id, quiz_name, plays
and the second one called quizes taken with:
session_id, quiz_id
and I would like to store count of rows, inside of plays column in table quizes, but I have no clue how to do it.
In more detail, what I am trying to achieve, is that on every update/insert into quizes_taken, in table quizes, the play" column updates with the row count of that quiz's ID from table quizes_taken.
If someone could explain how to achieve it, I'd be grateful!
Thanks in advance!
you could make a view or materialized view for the expected result output,
CREATE OR REPLACE VIEW AS quizes_live_update AS
SELECT a.id , a.quiz_name, COUNT(b.quiz_id) as plays
FROM quizes a
JOIN quizes_taken b ON a.id = b.quiz_id
GROUP BY a.id, a.quiz_name
Postgres: Create view
Although, if you need to proceed with tables approach, you can set up some upsert triggers
on quizes_taken table to perform update and insert on quizes table, plays column.

How to Link 2 Sheets that have the same fields

I am looking for some help with trying to link 2 sheets that have a number of Filters that I have setup but are both sitting in separate tables. The reason this is because I have a number of aggregated columns that are different for the 2 tables and want to keep this separately as I will be building more sheets as I go along.
The filters that are the same within the 2 sheets are the following:
we_date
product
manager
patch
Through the data manager I managed to create an association between the 2 tables for we_date but from reading on this site and other searches on Google I can't make any associations between these tables and this is where I am stuck.
The 2 sheets will now allow me to filter using the we_date, but if I use the filters for product, manager or patch then nothing happens on my 2nd sheet as they are not linked.
Currently in my data load editor I have 2 sections of select queries like the following:
Table1
QUALIFY *;
w:
SELECT
*
FROM
table1
;
UNQUALIFY *;
Table2
QUALIFY *;
w_c:
SELECT
*
FROM
table2
;
UNQUALIFY *;
I would really appreciate if somebody could advise a fix on the issue I am having.
In Qlik, field names of identical values from different tables are automatically associated.
When you're calling Qualify *, you're actually renaming all field names and explicitly saying NOT to associate.
Take a look at the Qlik Sense documentation on Qualify *:
The automatic join between fields with the same name in different
tables can be suspended by means of the qualify statement, which
qualifies the field name with its table name. If qualified, the field
name(s) will be renamed when found in a table. The new name will be in
the form of tablename.fieldname. Tablename is equivalent to the label
of the current table, or, if no label exists, to the name appearing
after from in LOAD and SELECT statements.
We can use as to manually reassign field names.
SELECT customer_id, private_info as "private_info_1", favorite_dog from table1;
SELECT customer_id, private_info as "private_info_2", car from table2;
Or, we can correctly use Qualify. Example:
table1 and table2 have a customer_id field, and private_info field. We want customer_id field to be the associative value, and private_info to not be. We would use QUALIFY on private_info, which Qlik would then rename based on file name.
QUALIFY private_info;
SELECT * from table1;
SELECT * from table2;
The following field names would then be: customer_id (associated), and table1.private_info, and table2.private_info

How to sort table alphabetically by name initial?

I have a table contains columns 'employeename' and 'id', how can I sort the 'employeename' column following alphabetical order of the names initial?
Say the table is like this now:
employeename rid eid
Dave 1 1
Ben 4 2
Chloe 6 6
I tried the command ORDER BY, it shows what I want but when I query the data again by SELECT, the showed table data is the same as original, indicting ORDER BY does not modify the data, is this correct?
SELECT *
FROM employee
ORDER BY employeename ASC;
I expect the table data to be modified (sorted by names alphabetical order) like this:
employeename rid eid
Ben 4 2
Chloe 6 6
Dave 1 1
the showed table data is the same as original, indicting ORDER BY does not modify the data, is this correct?
Yes, this is correct. A SELECT statement does not change the data in a table. Only UPDATE, DELETE, INSERT or TRUNCATE statements will change the data.
However, your question shows a misconception on how a relational database works.
Rows in a table (of a relational database) are not sorted in any way. You can picture them as balls in a basket.
If you want to display data in a specific sort order, the only (really: the only) way to do that is to use an ORDER BY in your SELECT statement. There is no alternative to that.
Postgres allows to define a VIEW that includes an ORDER BY which might be an acceptable workaround for you:
CREATE VIEW sorted_employee;
AS
SELECT *
FROM employee
ORDER BY employeename ASC;
Then you can simply use
select *
from sorted_employees;
But be aware of the drawbacks. If you run select * from sorted_employees order by id then the data will be sorted twice. Postgres is not smart enough to remove the (useless) order by from the view's definition.
Some related questions:
Default row order in SELECT query - SQL Server 2008 vs SQL 2012
What is the default SQL result sort order with 'select *'?
Is PostgreSQL order fully guaranteed if sorting on a non-unique attribute?
Why do results from a SQL query not come back in the order I expect?

Merge SQL to Exclude Duplicate Records So Merge 2nd time Doesn't Fail

I have three tables and only one that I directly control and am doing a MERGE between them. See my abbreviated but working example here (sqlfiddle example).
I am doing a MERGE between table 1 and Table 2 to Table 3. Table 1 has duplicate data which the MERGE (erroneously) can handle on the first run (insert) but fails with this message on the second run (update).
The MERGE statement attempted to UPDATE or DELETE the same row more
than once.
My question is, can the MERGE be written to either use an EXCEPT such as
SELECT AdFull FROM [dbo].[Users] WHERE AdFull IS NOT NULL
EXCEPT
SELECT AdFull FROM [dbo].[Users]
WHERE AdFull IS NOT NULL
GROUP BY AdFull
HAVING COUNT(*) = 1
or a different Join to only show users that are not duplicated? Or even a way to select a specific one of the duplicates?
Answered Questions
MERGE is a working Insert due to the nature of Fiddle. But due (AFAIK) to the stateless nature of fiddle one never sees the error in Fiddle on a second run, because a merge never happens with the data, only inserts.
Ignore Rows: Actually I would eventually like to use an individual duplicate row via divining of one based on a condition. The actual data table I am dealing with away from the fiddle example has more columns and it would be nice to maybe select a specific row in a duplicate set due to a specific condition.
The example doesn't bare it out, but yes the duplicates are due to the computed AdFull column. Think of a system adding a temp employee, that user gets a row. Then the temp employee gets hired on as fulltime, keeps the ad account but then gets another row in the user table. Yes I know it shouldn't happen. So that is how a duplicate comes about.
(Duplicate values Table 3) Table three is a result table that can be cleaned out for any duplicates to start this process afresh.
In your MERGE statement can you do something similar this?
MERGE INTO [dbo].Table3 AS T3
USING
(
SELECT
AdFull,
MAX(StartedOn)
FROM [dbo].Table2 AS [ad]
GROUP BY AdFull
) AS T2
ON (T2.AdFull = T3.AdFull)
WHEN MATCHED THEN UPDATE blah
WHEN NOT MATCHED THEN INSERT blah
Using the MAX aggregate with a GROUP BY should give you only the information from when the temp was hired on. Then if the AdFull matches you can simply UPDATE Table3 with the most recent information and if there is no match then INSERT a new row.
UPDATE: If I fail to mention that MERGE should be used with caution I will take flak from #AaronBertrand.

SQL Server 2008 View Columns match to underlying Table Columns

I've been attempting to write some SQL code that when provided with a view will locate the columns that the view columns reference and work out if there are any indexes on those columns. The end aim is to provide users with a list of columns it would be possible to use when querying the view.
Currently though I can only find the columns that the view uses (and by extension their indexes) but I cant match them back to the index's columns.
For example:
I have TableA, which has 5 Columns: ID, Name, Val1, Val2, TableBID
I have TableB, which has 3 Columns: ID, Name, Code
I then create a view, View1, which is:
SELECT A.ID,
Name,
Val1
FROM TableA A
INNER JOIN TableB ON A.TableBID = B.ID
WHERE B.Code = 'AAA'
When I query for references using:
SELECT *
FROM sys.dm_sql_referenced_entities('dbo.View1', 'OBJECT')
I'll get a list of the Table/Column references within it, but no indication of which View Column references what.
Is there any way I can access the information I need, bear in mind I cannot do name matching as the columns in the Alias may use aliases and therefore may not have the same names as the underlying data.
I'm using SQL Server 2008 SP1 if that has any impact.
Rename columns in view using unique combination Tablename + '_' + ColumnName for every view column. Then you can split views column onto table and column.