Where function on a virtual column in a union query - sql

I am new to sql and I need a little help. I have got a union query with 3 tables. I have got a virtual column so I can tell which table each row is from. I would like to be able to filter this virtual column to show only rows from a specific table.
I am using Microsoft Access and this is what I have so far:
SELECT Table1 as Table_Name, Table1.1
FROM Table1
UNION ALL
SELECT Table2 as Table_Name, Table2.1
FROM Table2
UNION ALL
SELECT Table3 as Table_Name, Table3.1
FROM Table3
UNION ALL
WHERE Table_Name = Form1.TextBox
ORDER BY Table1.1;
I am trying to link this to a listbox on a form and then have some textboxs to filter results.

How about:
SELECT * FROM
( SELECT Table1 as Table_Name, Table1.1
FROM Table1
UNION ALL
SELECT Table2 as Table_Name, Table2.1
FROM Table2
UNION ALL
SELECT Table3 as Table_Name, Table3.1
FROM Table3 ) q
WHERE Table_Name = Forms!Form1!TextBox
ORDER BY Table1.1;
See: http://access.mvps.org/access/forms/frm0031.htm

Related

Dynamic from clause

I have a table in which one column represent a name of a table in my db.
TableA
| tableName |
-------------
| table 1 |
| table 2 |
| ....... |
| table n |
What I need to do is to count all the records that are inside each table listed in tableA.
What I managed to do so far is this:
select count(*)
from (
select tableName
from tableA
) tables
but this is wrong because it counts the number of rows in the tableA table, which is not what I need.
The list of table don't have any relationship pretty much so there are no join operations, I just need to add to a counter the number of all records in each table.
Can that be done with a plain sql query? I'm using postgresql but would like to come up with a solution that doesn't depend on any db vendor.
select sum(row_count) as totalRecords
from(
select table_schema,
table_name,
(xpath('/row/cnt/text()', xml_count))[1]::text::int as row_count
from (
select table_name, table_schema,
query_to_xml(format('select count(*) as cnt from %I.%I', table_schema, table_name), false, true, '') as xml_count
from information_schema.tables t
join tableA ta on ta.tablename = t.table_name
)t
) t
A pure SQL solution that works in about any DBMS? Well, as you know you cannot simply query the table names from your control table and use these in a SQL FROM clause, because the table names in the control table are data while the table names in the FROM cause are structure, so to say.
As you should know your database, however, you can use the table names known to you and compare them to the entries in your control table:
select 'TABLE_1', count(*) from table_1 having 'TABLE_1' in (select tablename from tablea)
union all
select 'TABLE_2', count(*) from table_2 having 'TABLE_2' in (select tablename from tablea)
union all
select 'TABLE_3', count(*) from table_3 having 'TABLE_3' in (select tablename from tablea)
union all
select 'TABLE_4', count(*) from table_4 having 'TABLE_4' in (select tablename from tablea)
union all
select 'TABLE_5', count(*) from table_5 having 'TABLE_5' in (select tablename from tablea)
This query must be altered when new tables get added to the database. As adding tables to a database is something that happens seldom if ever, this shouldn't be an issue.
Demo: https://dbfiddle.uk/Dfk9nIFo

how can we select data from two or more tables if similar data is not present in both tables(without join)

I need solution for this type query.Means this query is not real but I need to fetch data like this:(except join and union)
select a b,c
from (table1 or table2)
where name="rohit";
it's simple to do with union
select *
from t1
where t1.name='a'
union (all)
select *
from t2
where t2.name='a'
If union and join is not allowed you can try select both table and create kind of union via GROUP BY trick. Like this
select *
from t1, t2
where t1.name='a' or t2.name='a'
group by (case t1.name
when 'a' then CONCAT('t1',t1.id)
else CONCAT('t2',t2.id) end case)
Haven't tested though. sqlfiddle.com somehow doesn't work showing errors when I try to execute a query like this

Comparing Two tables without knowing columns information

If I have two tables A and B. I want to know if this table are same or not ?
i.e check does columns match ?
and does data match ?
SELECT *
FROM
(
(SELECT * FROM Table1
MINUS
SELECT * FROM Table2)
UNION ALL
(SELECT * FROM Table2
MINUS
SELECT * FROM Table1)
)
Query USER_TAB_COLUMNS for each table
SELECT table_name, column_name,
FROM USER_TAB_COLUMNS
WHERE table_name = 'MYTABLE'
And you can compare it for matching columns .
(hawk's answer will do it in one step.)

select first N distinct rows without inner select in oracle

I have something like the following structure: Table1 -> Table2 relationship is 1:m
I need to perform queries similar to the next one:
select Table1.id from Table1 left outer join Table2 on (Table1.id1 = Table2.id2) where Table2.name like '%a%' and rownum < 11
i.e. I want first 10 ids from Table 1 which fulfils conditions in Table2. The problem is that I've to use distinct, but the distinct clause applies after 'rownum < 11', so the result could be e.g. 5 records even if their number is more than 10.
The apparent solution is to use the following:
select id from ( select Table1.id from Table1 left outer join Table2 on (Table1.id1 = Table2.id2) where Table2.name like '%a%' ) where rownum < 11
But I'm afraid of performance of such a query. If Table1 contains about 300k records, and Table2 contains about 700k records, wouldn't such a query be really slow?
Is there another query, but without inner select? Unluckily, I want to avoid using inner selects.
Unluckily, I want to avoid using inner
selects
With having the WHERE clause on TABLE2, you are filtering the select to an INNER JOIN (ie. since Table2.name IS null <> Table2.name like '%a%' you will only get results where the join is INNER to one another. Also, the %a% without a function based index will result in a full table scan on each iteration.
but #lweller is completely correct, to do the query correctly you will need to use a subquery. keep in mind, without an ORDER BY you have no guarantee of the order of your top X records (it may always 'appear' that the values conform to the primary key or whatnot, but there is no guarantee.
WITH TABLE1 AS(SELECT 1 ID FROM DUAL
UNION ALL
SELECT 2 ID FROM DUAL
UNION ALL
SELECT 3 ID FROM DUAL
UNION ALL
SELECT 4 ID FROM DUAL
UNION ALL
SELECT 5 ID FROM DUAL) ,
TABLE2 AS(SELECT 1 ID, 'AAA' NAME FROM DUAL
UNION ALL
SELECT 2 ID, 'ABB' NAME FROM DUAL
UNION ALL
SELECT 3 ID, 'ACC' NAME FROM DUAL
UNION ALL
SELECT 4 ID, 'ADD' NAME FROM DUAL
UNION ALL
SELECT 1 ID, 'BBB' NAME FROM DUAL
) ,
sortable as( --here is the subquery
SELECT
Table1.ID ,
ROW_NUMBER( ) OVER (ORDER BY Table2.NAME NULLS LAST) ROWOverName , --this wil handle the sort
table2.name
from
Table1
LEFT OUTER JOIN --this left join it moot, pull the WHERE table2.name into the join to have it LEFT join as expected
Table2
on
(
Table1.id = Table2.id
)
WHERE
Table2.NAME LIKE '%A%')
SELECT *
FROM sortable
WHERE ROWOverName <= 2;
-- you can drop the ROW_NUMBER( ) analytic function and replace the final query as such (as you initially indicated)
SELECT *
FROM sortable
WHERE
ROWNUM <= 2
ORDER BY sortable.NAME --make sure to put in an order by!
;
You don't need DISTINCT here at all, and there is nothing bad in subqueries as such.
SELECT id
FROM Table1
WHERE id IN
(
SELECT id
FROM Table2
WHERE name LIKE '%a%'
)
AND rownum < 11
Note that the order is not guaranteed. To guarantee order, you have to use a nested query:
SELECT id
FROM (
SELECT id
FROM Table1
WHERE id IN
(
SELECT id
FROM Table2
WHERE name LIKE '%a%'
)
ORDER BY
id -- or whatever else
)
WHERE rownum < 11
There is no way to do it without nested queries (or the CTE).
For me there is no reason to be afraid of performance. I think the sub select ist the best way to solve your problem. And if you want don't trust me, take a look at explain plan of your query and you will see that it behave not so bad as you might think.

Can you define values in a SQL statement that you can join/union, but are not stored in a table outside of the statement?

I'm trying to create a query and need to join against something that I can define values in without creating a table.
I'll attempt to describe what I'm trying to do:
table1
-------
fieldA
is joined on fieldA with
table2
-------
(titles for FK in table 1)
Table1 has values outside of what exists in table2
I want to add an additional 'table' to be unioned with table2 and then joined with table 1
Thanks
Sure, you can use a UNION ALL inside a subselect and join with the result of that. Something like this might do the trick:
SELECT *
FROM table1 T1
JOIN (
SELECT titles, stuff
FROM table2
UNION ALL
SELECT 'foo' AS titles, 'foostuff' AS stuff
UNION ALL
SELECT 'bar' AS titles, 'barstuff' AS stuff
) T2
ON T1.id = T2.titles
Note that the columns in the UNION ALL must be of the same type and in the same order. The column names don't have to match though.
Looks like you want to add arbitrary results to your query?
select
id,
titles
from
table1 t1
inner join table2 t2
on t2.titles = t1.titles
union (
(select 100, 'Dogs' from dual)
union
(select 200, 'Pigs' from dual)
union
(select 300, 'Sheep' from dual)
)
That's an oracle flavour, for other RDBMS' there will be an equivalent to dual
If you're using a modern Oracle version, there is an even neater solution
WITH arbitrary_data AS (
SELECT 100 id, 'Dogs' titles FROM DUAL
UNION ALL SELECT 200, 'Pigs' FROM DUAL
UNION ALL SELECT 300, 'Sheep' FROM DUAL
)
SELECT
id,
titles
FROM
table1 t1
inner join table2 t2
on t2.titles = t1.titles
inner join arbitrary_data ad
on ad.titles = t1.titles