field values as columns from master detail in PostgreSQL - postgresql

i got two tables in a master-detail relation and want to select all data in a single select query.
table "person":
id;name
1;Allen
2;Bert
3;Chris
table "connectivity":
id;personId;type;value
1;1;phone;+123456789
2;1;mail;allen#allen.allen
3;2;mail;bert#bert.bert
4;3;phone;+987654321
5;3;fax;+987654322
The query output should be something like
person.id;person.name;phone;mail;fax
1;Allen;+123456789;allen#allen.allen;
2;Bert;;bert#bert.com;
3;Chris;+987654321;;+987654322
Any idea possibly without writing some function?
It should dynamically add the colummns when the detail-table is extended. E.g. adding a row to the detail table like
6;2;icq;0123456789
My prefered solution would fit into a select-query.
Thanks!
Patrick

It is not possible to add columns to a static SQL query.
The model you are using is called "Entity–attribute–value model". You can google for details on its different implementations.
The only "easy" way (I can think of) to have many dynamic properties per object in SQL is to dump them all into a single structure like HSTORE, JSON(B), BLOB... In this case the output will loke like:
id;name;params
1;Allen;{"phone":"+123456789", "email":"allen#allen.allen"};
2;Bert;{"email":"bert#bert.com"};
3;Chris;{"phone":"+987654321", "fax":"+987654322"};

You need a JOIN and a CASE to select the values you need. Something like this:
SELECT person.id,
person.name,
CASE connectivity.type WHEN 'phone' THEN value END AS phone,
CASE connectivity.type WHEN 'mail' THEN value END AS mail,
CASE connectivity.type WHEN 'fax' THEN value END AS fax
FROM person
JOIN connectivity ON person.id = connectivity.personId;
Offtopic: Don't use a mix of UPPER and lower case, PostgreSQL only uses lower case unless you put everything between "double quotes".

select
p.name,
phone.value phone,
mail.value mail
from person p
left join connectivity phone on phone.personid = p.id and phone.type = 'phone'
left join connectivity mail on mail.personid = p.id and mail.type = 'mail'

Related

Laravel 4.2 order by another collections field or result of a function

I have a mongo database and I'm trying to write an Eloquent code to change some fields before using them in WHERE or ORDER BY clauses. something like this SQL query:
Select ag.*, ht.*
from agency as ag inner join hotel as ht on ag.hotel_id = ht.id
Where ht.title = 'OrangeHotel'
-- or --
Select ag.*, ht.*
from agency as ag inner join hotel as ht on ag.hotel_id = ht.id
Order by ht.title
sometimes there is no other table and I just need to use calculated field in Where or Order By clause:
Select *
from agency
Where func(agency_admin) = 'testAdmin'
Select *
from agency
Order by func(agency_admin)
where func() is my custom function.
any suggestion?
and I have read Laravel 4/5, order by a foreign column for half of my problem, but I don't know how can I use it.
For the first query: mongodb only support "join" partially with the aggregation pipeline, which limits your aggregation in one collection. For "join"s between different collections/tables, just select from collections one by one, first the one containing the "where" field, then the one who should "join" with the former, and so on.
The second question just puzzled me for some minutes until I see this question and realized it's the same as your first question: sort the collection containing your sort field and retrive some data, then go to another.
For the 3rd question, this question should serve you well.

Converting complex query with inner join to tableau

I have a query like this, which we use to generate data for our custom dashboard (A Rails app) -
SELECT AVG(wait_time) FROM (
SELECT TIMESTAMPDIFF(MINUTE,a.finished_time,b.start_time) wait_time
FROM (
SELECT max(start_time + INTERVAL avg_time_spent SECOND) finished_time, branch
FROM mytable
WHERE name IN ('test_name')
AND status = 'SUCCESS'
GROUP by branch) a
INNER JOIN
(
SELECT MIN(start_time) start_time, branch
FROM mytable
WHERE name IN ('test_name_specific')
GROUP by branch) b
ON a.branch = b.branch
HAVING avg_time_spent between 0 and 1000)t
GROUP BY week
Now I am trying to port this to tableau, and I am not being able to find a way to represent this data in tableau. I am stuck at how to represent the inner group by in a calculated field. I can also try to just use a custom sql data source, but I am already using another data source.
columns in mytable -
start_time
avg_time_spent
name
branch
status
I think this could be achieved new Level Of Details formulas, but unfortunately I am stuck at version 8.3
Save custom SQL for rare cases. This doesn't look like a rare case. Let Tableau generate the SQL for you.
If you simply connect to your table, then you can usually write calculated fields to get the information you want. I'm not exactly sure why you have test_name in one part of your query but test_name_specific in another, so ignoring that, here is a simplified example to a similar query.
If you define a calculated field called worst_case_test_time
datediff(min(start_time), dateadd('second', max(start_time), avg_time_spent)), which seems close to what your original query says.
It would help if you explained what exactly you are trying to compute. It appears to be some sort of worst case bound for avg test time. There may be an even simpler formula, but its hard to know without a little context.
You could filter on status = "Success" and avg_time_spent < 1000, and place branch and WEEK(start_time) on say the row and column shelves.
P.S. Your query seems a little off. Don't you need an aggregation function like MAX or AVG after the HAVING keyword?

PostgreSQL: return all rows including duplicates

Some background: my client is requesting a way to find out who is using his computers. Each computer user has a unique barcode attached to their account which ends up in a log file (recording date and time among other things), but the log file he looks at does not report the residence for these users which he needs. I have a separate read-only PostgreSQL database that I can search against to find the residence of the user using their barcode. I setup a web form using a textarea field to allow the client to input a list of barcodes. I then capture the entire string into a variable and put together a SQL query that looks like this:
SELECT
n.last_name as name,
p.barcode as barcode,
p.home as residence
FROM db.pt_view p JOIN db.pt_record_fullname n ON p.id = n.patron_record_id
WHERE p.barcode IN ('25260045344400','25233423433332','25233423433332','...)
This works, but the "IN" operator of course removes all of the duplicate barcodes. I need all of the barcodes (duplicate or not) to match up to the number of entries in the log file. A barcode can appear many times in the log at different dates and times. Using this query above, I entered in 918 barcodes and only returned 450.
I'm a relative PostgreSQL and database noob, so I'm sure there's a better way to handle this and return all of the records (with duplicates). Thanks in advance for any help.
If IN isn't doing what you want, perhaps the on-the-fly capabilities of VALUES as a subquery will do.
SELECT
n.last_name as name, /* don't recommend using reserved word name this way */
p.barcode as barcode,
p.home as residence
FROM db.pt_view p
JOIN db.pt_record_fullname n ON p.id = n.patron_record_id
JOIN (VALUES('25260045344400'),('25233423433332'),('25233423433332') /* , ...*/))
AS codes(barcode)
ON p.barcode=codes.barcode;
try cartesian product
if you use JOIN without ON,will create a cartesian product,this is a product ALL x ALL rows and use a condicional to end.
somethink like:
SELECT
n.last_name as name,
p.barcode as barcode,
p.home as residence
FROM db.pt_view p JOIN db.pt_record_fullname n
WHERE p.barcode IN ('25260045344400','25233423433332','25233423433332','...) and p.id = n.patron_record_id
PD: my english is not good xD

Transact-SQL Ambiguous column name

I'm having trouble with the 'Ambiguous column name' issue in Transact-SQL, using the Microsoft SQL 2012 Server Management Studio.
I´ve been looking through some of the answers already posted on Stackoverflow, but they don´t seem to work for me, and parts of it I simply don´t understand or loses the general view of.
Executing the following script :
USE CDD
SELECT Artist, Album_title, track_title, track_number, Release_Year, EAN_code
FROM Artists AS a INNER JOIN CD_Albumtitles AS c
ON a.artist_id = c.artist_id
INNER JOIN Track_lists AS t
ON c.title_id = t.title_id
WHERE track_title = 'bohemian rhapsody'
triggers the following error message :
Msg 209, Level 16, State 1, Line 3
Ambiguous column name 'EAN_code'.
Not that this is a CD database with artists names, album titles and track lists. Both the tables 'CD_Albumtitles' and 'Track_lists' have a column, with identical EAN codes. The EAN code is an important internationel code used to uniquely identify CD albums, which is why I would like to keep using it.
You need to put the alias in front of all the columns in your select list and your where clause. You're getting that error because one of the columns you have currently is coming from multiple tables in your join. If you alias the columns, it will essentially pick one or the other of the tables.
SELECT a.Artist,c.Album_title,t.track_title,t.track_number,c.Release_Year,t.EAN_code
FROM Artists AS a INNER JOIN CD_Albumtitles AS c
ON a.artist_id = c.artist_id
INNER JOIN Track_lists AS t
ON c.title_id = t.title_id
WHERE t.track_title = 'bohemian rhapsody'
so choose one of the source tables, prefixing the field with the alias (or table name)
SELECT Artist,Album_title,track_title,track_number,Release_Year,
c.EAN_code -- or t.EAN_code, which should retrieve the same value
By the way, try to prefix all the fields (in the select, the join, the group by, etc.), it's easier for maintenance.

How to do a joined query in the ZF tables interface?

I have the db and my tables look like this:
alt text http://img15.imageshack.us/img15/2568/stackdijag.png
What I want to do is to get all models where manufacturers name column starts with A.
Which means that that simple part of query should be like $manufacturers->fetchAll("name LIKE '$letter%'");
I am trying to accomplish this with ZF relations but it ain't going, so any kind of help is welcome...
$models = new Models();
$select = $models->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->setIntegrityCheck(false)
->join(array("a"=>"manufacturers"), 'models.manufacturer_id = a.id',
array("man_name"=>"name", "man_description"=>"description"))
->where("a.name LIKE 'A%'");
$rowset = $models->fetchAll($select);
Unfortunately the Zend_Db_Table relationships interface doesn't have much intelligence in it related to creating joined queries from its declared reference map. The community-contributed solution for complex queries is the Zend_Db_Table_Select query factory.
Note you have to give column aliases for manufacturer's name and description, or else these columns will suppress the model's name and description in the associative array for the row data. You should name columns distinctly to avoid this.
But in your case, I'd skip the table interface and the select interface, and simply execute an SQL query directly using the Db adapter:
$data = $db->fetchAll("
SELECT m.*, a.name AS man_name, a.description AS man_description
FROM Models m JOIN Manufacturers a ON m.manufacturer_id = a.id
WHERE a.name LIKE 'A%'");
You'll get the data back as a simple array of associative arrays, not as a Zend_Db_Table_Rowset. But since a joined rowset isn't writeable anyway, you haven't sacrificed much.