PostgreSQL libpq: PQNumber and column aliases - sql

In a Postgres libpq sql there is a function PQfnumber: Returns the column number associated with the given column name.
Lets say I have a select:
select a.*, b.* from a, b where a.id = b.id
now if I will call
number = PQfnumber(pgresult, "a.id");
it will return -1.
Correct way is to call:
number = PQfnumber(pgresult, "id");
which returns position of a.id. So how would I need to call the function to get column number of b.id?
The only way around it seems to write a different select:
select a.id as a_id, a.*, b.id as b_id, b.* from a, b where a.id = b.id
number = PQfnumber(pgresult, "b_id");
Any other way around this?

No, you've found the right way.
Of course, with a.id = b.id in an inner join (as in the example code), why would you care which column you were looking at? Also, there are good reasons not to have just an id column as the primary key of every table. Even if a lot of tables have single-column integer keys, if you consistently name columns which hold a primary key to a given table, terser and more efficient syntax like JOIN ... USING is available.

If you use construct like this:
number = PQfnumber(pgresult, "a.id");
then you're query should contain a column alias like this:
SELECT a.id AS "a.id", b.* FROM a, b WHERE a.id = b.id;
You do have ambiguity in your code, should you tried such query in the PL/pgSQL language, you would have received the 42702: ambiguous_column exception.
I see the only way out here — you should give unique aliases for all the ambitious columns of your query. In fact, it is a good practice to give aliases for all columns, I always do so.

Related

PostgreSQL query to check if a row is referenced from multiple tables

I have one master table A, and two different sub tables (B, C) which is referenced by foreign key in table A, I want to check if a row exists with foreign key fk-1 in tables B or C.
I tried by selecting rows from A with exists clause on B & C which are selected using the fk-1 further OR'ed together and found the result.
SELECT A.id FROM A where A.id = fk-1 AND
(
EXISTS (select B.id from B where B.fk_1 = fk-1)
OR EXISTS (select C.id from C where C.fk_1 = fk-1)
);
Can this be optimised or is there any better ways to do this.
Thanks in advance.
For a single check that is the fastest given you indexed A.id, B.fk_1 and C.fk_1
A common pitfall is calling this SQL for every single row you might want to check. The check can be way faster if all rows are checked at once. (Faster per row checked)
So in case you want to check a bunch of them at the same time, you could do:
SELECT A.id FROM A WHERE A.id IN (
SELECT B.fk_1 FROM B [WHERE xxx]
UNION SELECT C.fk_1 FROM C [WHERE xxx])
Use [WHERE xxx] to place a WHERE to filter the relevant results you might want.
One recommeded check would be "WHERE B.fk_1 IS NOT NULL" to filter out records without FK.

How to populate query with result from different table?

I have two tables. Table A and table B. Table A has a column that is a reference to the primary key to table B. I want to run a select query on table A and then populate the column that referrers to B with all of the data in that row of B.
SELECT * from A a LEFT JOIN B b ON a."b_id" = b."id" WHERE ...
That gives a result with each row containing all of the columns of A and all of the columns of B. It is a confusing mess to figure out which column is from which table. I want to be able to do something like.
row.A."column name"
row.B."column name"
I don't want to have to rename every single column using AS. There must be a better way to do this.
Not a 100% sure what your asking but what I think your asking is.
You want a way to have only column B values to show? If so you could do:
SELECT B.*
FROM A
JOIN B
ON A.b_id = B.id
That will only get you the B columns and data, If you want A also maybe do but you want to have it separate from b maybe do:
SELECT B.*,'|' AS ['|'], A.*
FROM A
JOIN B
ON A.b_id = B.id
Hopefully this is helpful, if not to you maybe another reader.

mysql query add [something]_ infront of all table rows when grabbing multiple tables

Example of what I want to do:
select a.* as a_, b. as b_* FROM a, b WHERE a.id = b.id
Cannot be done automatically in SQL. Either type or generate the following:
SELECT a.field AS a_field, a.field2 AS a_field2, ...
At any rate, listing the fields by hand is good practice anyways.

Complex SQL queries (DELETE)?

I'm working with three tables, and for simplicity's sake let's call them table A, B, and C. Both tables A and B have a column called id, as well as one other column, Aattribute and Battribute, respectively. Column c also has an id column, and two other columns which hold values for A.id and B.id. Now, in my code, I have easy access to values for both Aattribute and Battribute, and want to delete the row at C, so effectively I want to do something like this:
DELETE FROM C WHERE aid=(SELECT id FROM A WHERE Aattribute='myvalue') AND bid=(SELECT id FROM B WHERE Battribute='myothervalue')
But this obviously doesn't work. Is there any way to make a single complex query, or do I have to run three queries, where I first get the value of A.id using a SELECT with 'myvalue', then the same for B.id, then use those in the final query?
[Edit: it's not letting me comment, so in response to the first comment on this: I tried the above query and it did not work, I figured it just wasn't syntactically correct. Using MS Access, for what it's worth. ]
You must use IN instead of =.
DELETE
FROM C
WHERE aid IN
(SELECT id
FROM A
WHERE Aattribute='myvalue'
)
AND bid IN
(SELECT id
FROM B
WHERE Battribute='myothervalue'
)

SQL (any) Request for insight on a query optimization

I have a particularly slow query due to the vast amount of information being joined together. However I needed to add a where clause in the shape of id in (select id from table).
I want to know if there is any gain from the following, and more pressing, will it even give the desired results.
select a.* from a where a.id in (select id from b where b.id = a.id)
as an alternative to:
select a.* from a where a.id in (select id from b)
Update:
MySQL
Can't be more specific sorry
table a is effectively a join between 7 different tables.
use of * is for examples
Edit, b doesn't get selected
Your question was about the difference between these two:
select a.* from a where a.id in (select id from b where b.id = a.id)
select a.* from a where a.id in (select id from b)
The former is a correlated subquery. It may cause MySQL to execute the subquery for each row of a.
The latter is a non-correlated subquery. MySQL should be able to execute it once and cache the results for comparison against each row of a.
I would use the latter.
Both queries you list are the equivalent of:
select a.*
from a
inner join b on b.id = a.id
Almost all optimizers will execute them in the same way.
You could post a real execution plan, and someone here might give you a way to speed it up. It helps if you specify what database server you are using.
YMMV, but I've often found using EXISTS instead of IN makes queries run faster.
SELECT a.* FROM a WHERE EXISTS (SELECT 1 FROM b WHERE b.id = a.id)
Of course, without seeing the rest of the query and the context, this may not make the query any faster.
JOINing may be a more preferable option, but if a.id appears more than once in the id column of b, you would have to throw a DISTINCT in there, and you more than likely go backwards in terms of optimization.
I would never use a subquery like this. A join would be much faster.
select a.*
from a
join b on a.id = b.id
Of course don't use select * either (especially never use it when doing a join as at least one field is repeated) and it wastes network resources to send unnneeded data.
Have you looked at the execution plan?
How about
select a.*
from a
inner join b
on a.id = b.id
presumably the id fields are primary keys?
Select a.* from a
inner join (Select distinct id from b) c
on a.ID = c.AssetID
I tried all 3 versions and they ran about the same. The execution plan was the same (inner join, IN (with and without where clause in subquery), Exists)
Since you are not selecting any other fields from B, I prefer to use the Where IN(Select...) Anyone would look at the query and know what you are trying to do (Only show in a if in b.).
your problem is most likely in the seven tables within "a"
make the FROM table contain the "a.id"
make the next join: inner join b on a.id = b.id
then join in the other six tables.
you really need to show the entire query, list all indexes, and approximate row counts of each table if you want real help