Consider i am using join on three tables to get a desired result-set...
Now in that result set, is there anyway that i can find out which row comes from which table...?
Update :
I see that i have phrased the question rather wrongly.... As pointed in one of the answers below, a result-set returned by join may will contain a row made up columns from multiple talbes...
So the question should actually be "Consider i am using union on three tables to get a desired result-set..."
You can add a table identifier column to each:
select 'A' as table_name, col1, col2 from A
union
select 'B' as table_name, col1, col2 from B
union
...
This returns a single result set which is handled by your application as any ordinary select statement:
while ( rows available ) {
row = fetchrow
if row.table_name == 'A' then
do special handling for table A
else if row.table_name == 'B' then
do special handling for table B
else if ...
}
The actual syntax is dependent on the language you are using, but most procedural languages follow the scheme above.
If you are asking this question, then your database is probably not structured correctly. (correctly being a subjective term).
A proper SQL query on a normalized database should not depend, nor be concerned with, where the data comes from.
Each row would be a combination of all tables, with null values being inserted in columns for left/right/outer joins which do not match the joining criteria. You could perhaps test if a column (from a particular table) is null, and derive from that that the non-null values must originate from the opposite table(s).
Then again, if you were actually performing an UNION, as Marcelo suggested, you would have to look at ancillary columns to determine the source of the data, as that information is lost in the combination.
Related
My scenario is as follows( in MySQL)
I have a table say table 1, which has 2 columns:
userID, column_acess
Table 2 which has a list of columns say col1,col2,col3, etc.
Now What I would like to do is use pymySQL to query table 1 for the columns a particular userID is allowed to acesss, by inspecting the column, acess field ( which will contain a comma seperated list of columns in tabl2), and use that result in another sql query ( which works on table2) to actually get the data from the respective columns a user is allowed to acess.
So essentially I would like something like:
Select (Select column_acess from tabl1 where user_ID='123') from table2
So inner query should return the list of columns say col1, col2, which would be used to select the columns in the outer query in table2
How do I do that in mySQL?
I strongly encourage you too read this post. You should either first store columns in variable or use dynamic sql query. Use SELECT result as COLUMN name in other SELECT
BTW your schema is not even in 1 NF since you don’t have atomic values in table 1. You should avoid that.
MySQL supports the granting of column-level privileges to users, using the standard grant statement.
I would suggest that you start with the documentation on this subject.
An alternative to using grant for columns is to create views for different user types. This is, in fact, the more general solution, because the views can filter rows as well as columns. The idea is that the underlying tables are not directly accessible. The views are, so all access needs to go through the views.
I am going through Ben Fortas "Teach yourself SQL in 10 minutes" book and it has grey box warning: "Subquery SELECT statements can only retrieve a single column. Attempting to return multiple columns will return an error."
Is this, in fact, commonly true for an RDMS? (Note that if this answer is correct then it is not true for all databases).
And why in the world would it ever be true? It seems like such a weird language restriction. Queries are expensive to compute, and the work to retrieve 3 columns is not particularly computationally different than the work to retrieve 1 (unless your RDMS stores your tables grouped by columns instead of grouped by rows).
In the answer that you link to, I would classify that as an "inline view" or "inline query", rather than a subquery.
That raises the question of what exactly a subquery is, of course.
Here's an example where you can indeed only return a single column.
select (select name from table where id = main_query.id),
id
from table main_query
Here's an example where you can return multiple columns. This seems to be to be unequivocally a subquery, of the "correlated" type.
select id
from table main_query
where (col1, col2) in (select a,b
from c
where c.x = main_query.y);
Here's an example where it doesn't matter how many columns are returned, and in fact any values are ignored:
select id
from table main_query
where exists (select a,b
from c
where c.x = main_query.y);
I think on balance I'd say that it is not true, but it depends on what your definition of a subquery is.
Scalar subqueries can return only one column. These are subqueries that are used wherever a single value is expected. This can be in almost any clause. For instance, as this non-sensical query uses them:
select (select count(*) from information_schema.tables), table_name
from information_schema.columns
where table_name = (select table_name from information_schema.columns order by rand() limit 1);
However, many subqueries are not scalar subqueries. These include:
Subqueries in the FROM clause.
Subqueries for a EXISTS and NOT EXISTS.
Subqueries that operator on a tuple when used in a comparison such as = and IN.
I am relatively new to coding so please have patience.
I am trying to combine data from 3 tables. I have managed to get some data back but it isn't what i need. Please see my example below.
select oid, rrnhs, idnam, idfnam, dte1, ta
as 'access type' from person
left join
(select fk_oid, min(dte), dte1, ta
from
((Select fk_oid,min(accessdate) as dte, accessdate1 as dte1, accesstype as ta
from vascularpdaccess
where isnull(accesstype)=false group by fk_oid)
union
(Select fk_oid, min(hpdate) as dte, hpdate as dte1, HPACCE as ta
from hdtreatment
where isnull(hptype)=false group by fk_oid)) as bla
group by fk_oid) as access
on person.oid=access.fk_oid
where person.rrnhs in (1000010000, 2000020000, 3000030000)
My understanding with a union is that the columns have to be of the same data type but i have two problems. The first is that accesstype and hpacce combine in to a the same column as expected, but i dont want to actually see the hpacce data (dont know if this is even possible).
Secondly, the idea of the query is to pull back a patients 'accesstype' date at the first date of hpdate.
I dont know if this even makes sens to you guys but hoping someone can help..y'all are usually pretty nifty!
Thanks in advance!
Mikey
All queries need to have the same number of columns in the SELECT statement. It looks like you first query has the max number of columns, so you will need to "pad" the other to have the same number of columns. You can use NULL as col to create the column with all null values.
To answer the question (I think) you were asking... for a UNION or UNION ALL set operation, you are correct: the number of columns and the datatypes of the columns returned must match.
But it is possible to return a literal as an expression in the SELECT list. For example, if you don't want to return the value of HPACCE column, you can replace that with a literal or a NULL. (If that column is character datatype (we can't tell from the information provided in the question), you could use (for example) a literal empty string '' AS ta in place of HPACCE AS ta.
SELECT fk_oid
, MIN(HPDATE) AS dte
, hpdate AS dte1
, NULL AS ta
-- -------------------- ^^^^
FROM hdtreatment
Some other notes:
The predicate ISNULL(foo)=FALSE can be more simply expressed as foo IS NOT NULL.
The UNION set operator will remove duplicate rows. If that's not necessary, you could use a UNION ALL set operator.
The subsequent GROUP BY fk_oid operation on the inline view bla is going to collapse rows; but it's indeterminate which row the values from dte1 and ta will be from. (i.e. there is no guarantee those values will be from the row that had the "minimum" value of dte.) Other databases will throw an exception/error with this statement, along the lines of "non-aggregate in SELECT list not in GROUP BY". But this is allowed (without error or warning) by a MySQL specific extension to GROUP BY behavior. (We can get MySQL to behave like other databases and throw an error of we specify a value for sql_mode that includes ONLY_FULL_GROUP_BY (?).)
The predicate on the outer query doesn't get pushed down into the inline view bla. The view bla is going to materialized for every fk_oid, and that could be a performance issue on large sets.
Also, qualifying all column references would make the statement easier to read. And, that will also insulate the statement from throwing an "ambiguous column" error in the future, when a column named (e.g.) ta or dte1 is added to the person table.
I have a special data environment where I need to be returned data in a certain way to populate a table.
This is my current query:
SELECT
bs_id,
IF(bs_board = 0, 'All Boards', (SELECT b_name FROM certboards WHERE b_id IN (REPLACE(bs_board, ';', ',')))) AS board
FROM boardsubs
As you can see I have an if statement then a special subselect.
The reason I have this is that the field bs_board is a varchar field containing multiple row IDs like so:
1;2;6;17
So, the query like it is works fine, but it only returns the first matched b_name. I need it to return all matches. For instance in this was 1;2 it should return two boards Board 1 and Board 2 in the same column. Later I can deal with adding a <br> in between each result.
But the problem I am dealing with is that it has to come back in a single column both name, or all names since the field can contain as many as the original editor selected.
This will not work the way you're thinking it will work.
Let's say bs_board is '1;2;3'
In your query, REPLACE(bs_board, ';', ',') will resolve to '1,2,3', which is a single literal string. This makes your final subquery:
SELECT b_name FROM certboards WHERE b_id IN ('1,2,3')
which is equivalent to:
SELECT b_name FROM certboards WHERE b_id = '1,2,3'
The most correct solution to the problem is to normalize your database. Your current system or storing multiple values in a single field is exactly what you should never do with an RDBMS, and this is exactly why. The database is not designed to handle this kind of field. You should have a separate table with one row for each bs_board, and then JOIN the tables.
There are no good solutions to this problem. It's a fundamental schema design flaw. The easiest way around it is to fix it with application logic. First you run:
SELECT bs_id, bs_board FROM boardsubs
From there you parse the bs_board field in your application logic and build the actual query you want to run:
SELECT bs_id,
IF(bs_board = 0, 'All Boards', (SELECT b_name FROM certboards WHERE b_id IN (<InsertedStringHere>) AS board
FROM boardsubs
There are other ways around the problem, but you will have problems with sorting order, matching, and numerous other problems. The best solution is to add a table and move this multi-valued field to that table.
The b_id IN (REPLACE(bs_board, ';', ',')) will result in b_id IN ('1,2,6,7') which is different from b_id IN (1,2,6,7) which is what you are looking for.
To make it work either parse the string before doing the query, or use prepared statements.
I have seen many queries with something as follows.
Select 1
From table
What does this 1 mean, how will it be executed and, what will it return?
Also, in what type of scenarios, can this be used?
select 1 from table will return the constant 1 for every row of the table. It's useful when you want to cheaply determine if record matches your where clause and/or join.
SELECT 1 FROM TABLE_NAME means, "Return 1 from the table". It is pretty unremarkable on its own, so normally it will be used with WHERE and often EXISTS (as #gbn notes, this is not necessarily best practice, it is, however, common enough to be noted, even if it isn't really meaningful (that said, I will use it because others use it and it is "more obvious" immediately. Of course, that might be a viscous chicken vs. egg issue, but I don't generally dwell)).
SELECT * FROM TABLE1 T1 WHERE EXISTS (
SELECT 1 FROM TABLE2 T2 WHERE T1.ID= T2.ID
);
Basically, the above will return everything from table 1 which has a corresponding ID from table 2. (This is a contrived example, obviously, but I believe it conveys the idea. Personally, I would probably do the above as SELECT * FROM TABLE1 T1 WHERE ID IN (SELECT ID FROM TABLE2); as I view that as FAR more explicit to the reader unless there were a circumstantially compelling reason not to).
EDIT
There actually is one case which I forgot about until just now. In the case where you are trying to determine existence of a value in the database from an outside language, sometimes SELECT 1 FROM TABLE_NAME will be used. This does not offer significant benefit over selecting an individual column, but, depending on implementation, it may offer substantial gains over doing a SELECT *, simply because it is often the case that the more columns that the DB returns to a language, the larger the data structure, which in turn mean that more time will be taken.
If you mean something like
SELECT * FROM AnotherTable
WHERE EXISTS (SELECT 1 FROM table WHERE...)
then it's a myth that the 1 is better than
SELECT * FROM AnotherTable
WHERE EXISTS (SELECT * FROM table WHERE...)
The 1 or * in the EXISTS is ignored and you can write this as per Page 191 of the ANSI SQL 1992 Standard:
SELECT * FROM AnotherTable
WHERE EXISTS (SELECT 1/0 FROM table WHERE...)
it does what it says - it will always return the integer 1. It's used to check whether a record matching your where clause exists.
select 1 from table is used by some databases as a query to test a connection to see if it's alive, often used when retrieving or returning a connection to / from a connection pool.
The result is 1 for every record in the table.
To be slightly more specific, you would use this to do
SELECT 1 FROM MyUserTable WHERE user_id = 33487
instead of doing
SELECT * FROM MyUserTable WHERE user_id = 33487
because you don't care about looking at the results. Asking for the number 1 is very easy for the database (since it doesn't have to do any look-ups).
Although it is not widely known, a query can have a HAVING clause without a GROUP BY clause.
In such circumstances, the HAVING clause is applied to the entire set. Clearly, the SELECT clause cannot refer to any column, otherwise you would (correct) get the error, "Column is invalid in select because it is not contained in the GROUP BY" etc.
Therefore, a literal value must be used (because SQL doesn't allow a resultset with zero columns -- why?!) and the literal value 1 (INTEGER) is commonly used: if the HAVING clause evaluates TRUE then the resultset will be one row with one column showing the value 1, otherwise you get the empty set.
Example: to find whether a column has more than one distinct value:
SELECT 1
FROM tableA
HAVING MIN(colA) < MAX(colA);
If you don't know there exist any data in your table or not, you can use following query:
SELECT cons_value FROM table_name;
For an Example:
SELECT 1 FROM employee;
It will return a column which contains the total number of rows & all rows have the same constant value 1 (for this time it returns 1 for all rows);
If there is no row in your table it will return nothing.
So, we use this SQL query to know if there is any data in the table & the number of rows indicates how many rows exist in this table.
If you just want to check a true or false based on the WHERE clause, select 1 from table where condition is the cheapest way.
This means that You want a value "1" as output or Most of the time used as Inner Queries because for some reason you want to calculate the outer queries based on the result of inner queries.. not all the time you use 1 but you have some specific values...
This will statically gives you output as value 1.
I see it is always used in SQL injection,such as:
www.urlxxxxx.com/xxxx.asp?id=99 union select 1,2,3,4,5,6,7,8,9 from database;
These numbers can be used to guess where the database exists and guess the column name of the database you specified.And the values of the tables.
it simple means that you are retrieving the number first column from table ,,,,means
select Emply_num,Empl_no From Employees ;
here you are using select 1 from Employees;
that means you are retrieving the Emply_num column.
Thanks
The reason is another one, at least for MySQL. This is from the MySQL manual
InnoDB computes index cardinality values for a table the first time that table is accessed after startup, instead of storing such values in the table. This step can take significant time on systems that partition the data into many tables. Since this overhead only applies to the initial table open operation, to “warm up” a table for later use, access it immediately after startup by issuing a statement such as SELECT 1 FROM tbl_name LIMIT 1
This is just used for convenience with IF EXISTS(). Otherwise you can go with
select * from [table_name]
Image In the case of 'IF EXISTS', we just need know that any row with specified condition exists or not doesn't matter what is content of row.
select 1 from Users
above example code, returns no. of rows equals to no. of users with 1 in single column