Recently I've been working on some software which has a system in place that allows you to list specific data from an MSSQL table and display it in a web-based GUI. It has a few constrictions, though.
When comparing text, the only operators allowed are NOT NULL and LIKE.
Furthermore, every statement starts with SELECT * FROM MyTable WHERE.
The reason for that is the way the software we're using is programmed. Unfortunately, there isn't a way to change it and the developers don't seem to be planning on addressing the issue either.
This has been causing quite some trouble, but so far, there have always been ways to rewrite the statements.
Now, I've reached a point where I'm stuck. I've created a view that selects a specific subset of MyTable's rows. Now I want to display these
Tl;dr:
If I have this piece of code which I cannot modify, only append to:
SELECT * FROM MyTable WHERE
how do I perform an inner join with a different table from there, without using IN?
-
Thanks in advance!
Just for the laugh of it, I'd do something like that:
SELECT * FROM MyTable WHERE 0 = 1 UNION SELECT whatIWant FROM whereIWant
The 0 = 1 criteria discards all results from MyTable, only the right part of the union will return results. A problem is that you will still have to handle the columns from MyTable.
Use EXISTS
SELECT * FROM MyTable WHERE
exists (SELECT * from othertable as t2 where t2.col=MyTable.col)
Related
I have a table that contains several repair categories, and items that are associated with each repair category. I am trying to insert all the standard items from a specific repair category that don't already exist into a Details table.
TblEstimateDetails is a join table for an Estimate Table and StandardItem Table. And TblCategoryItems is a join table for the Repair Categories and their respective Standard Items.
For example in the attached image, Left side are all the Standard Items in a Repair Category, and Right side are all the Standard Items that are already in the EstimateDetails table.
Standard Items All vs Already Included
I need to be able to insert the 6 missing GUIDS from the left, and into the table on the right, and only for a specific estimate GID.
This is being used in an Access VBA script, which I will translate into the appropriate code once I get the sql syntax correct.
Thank you!
INSERT INTO TblEstimateDetails(estimate_GID, standard_item_GID)
SELECT
'55DEEE29-7B79-4830-909C-E59E831F4297' AS estimate_GID
, standard_item_GID
FROM TblCategoryItems
WHERE repair_category_GID = '32A8AE6D-A512-4868-8E1A-EF0357AB100E'
AND NOT EXISTS
(SELECT standard_item_GID
FROM TblEstimateDetails
WHERE estimate_GID = '55DEEE29-7B79-4830-909C-E59E831F4297');
Some things to try: 1) simplify to a select query to see if it selects the right records, 2) use a NOT IN statement instead of NOT EXISTS. There's no reason NOT EXISTS shouldn't work, I'd just try a different way if it isn't working.
SELECT '55DEEE29-7B79-4830-909C-E59E831F4297' AS estimate_GID,
standard_item_GID
FROM TblCategoryItems
WHERE repair_category_GID = '32A8AE6D-A512-4868-8E1A-EF0357AB100E'
AND standard_item_GID NOT IN
(SELECT standard_item_GID FROM TblEstimateDetails
WHERE estimate_GID = '55DEEE29-7B79-4830-909C-E59E831F4297');
Got it figured out. Access needs the subquery to be correlated to main query to work. So I set the WHERE clause in the subquery to equal the matching column in the main query. And I had to join the Estimates table so that it picked only the items in a specific estimate.
SELECT
'06A2E0A9-9AE5-4073-A856-1CCE6D9C48BB' AS estimate_GID
, CI.standard_item_GID
FROM TblCategoryItems CI
INNER JOIN TblEstimates E ON CI.repair_category_GID=E.repair_category_GID
WHERE E.repair_category_GID = '15238097-305E-4456-B86F-3787C9B8219B'
AND NOT EXISTS
(SELECT ED.standard_item_GID
FROM TblEstimateDetails ED
WHERE E.estimate_GID=ED.estimate_GID
);
I'm having some trouble with Access. I have a PHONES table with two very specific columns: Provider_prefix and client_prefix. I need to be able to generate a query that will give me every provider_prefix that is not on client_prefix (that is, there are no clients in the prefix area of that provider), and one that will do just the opposite: give me the prefixes that match. So far I've tried the following:
SELECT *
FROM PHONES INNER JOIN PHONES_2
ON PHONES.provider_prefix != PHONES_2.client_prefix;
Which will just fail.
I've also tried the following:
SELECT *
FROM PHONES
WHERE provider_prefix NOT IN (SELECT DISTINCT client_prefix
FROM PHONES)
Which, while technically working, throws zero, and my guess is that is happens because there are nulls in the columns (which are both Number-type).
Any ideas would be very appreciated.
A NOT IN clause tends to deal poorly with Null values (see this question).
The usual way to avoid this, is to rewrite to a NOT EXISTS clause.
SELECT *
FROM PHONES p
WHERE NOT EXISTS (SELECT 1
FROM PHONES s
WHERE s.client_prefix = p.provider_prefix)
We have a database that holds data for numerous customers. We want to give customers access to the database, but only to the data that belongs to them. Parsing the select to then insert in the where clause "and Company.Name = 'Acme'" strikes me as weak because SQL selects can be very complex and handling 100% of all cases may be difficult.
Is there some way to do the equivalent of (I know this is not valid SQL):
select * from * where Company.Name = 'Acme' and (passed_in_select)
You can nest a full select in as an inner part of a large select. Is there some way to do the above? This way it's a very simple restriction on the select and that is likely to work 100% of the time.
Here is a system solution called "virtual private database" for Oracle database:
https://docs.oracle.com/cd/B28359_01/network.111/b28531/vpd.htm
For other databases look whether there is similar built-in solution.
But there is very simple solution using the WITH clause:
WITH
tab_a__ AS (SELECT * FROM tab_a WHERE comp="xy"),
tab_b__ AS (SELECT * FROM tab_b WHERE comp="xy")
SELECT ... //original select
You just have to find all used tables in the select, add __ behind and add the CTEs to the WITH clause.
Notes: Some databases do not support WITH clause though it is an SQL standard. Some databases can have alias length limitation you could exceed by adding the suffix.
select * from
(
select * from table_a
) outer_table_a
where outer_table_a.col_a = 'test'
I do this sort of thing often especially when I want to perform some aggregation on the data in the inner query (sum, max, etc.) I do this with SQL Server, I do not know if it is valid with other DBMS but I would be surprised if it were not.
I don't know if I would rely on this approach to effectively grant permissions. Perhaps views would allow you lock things down a bit tighter. It sounds like you're planning to tack something on dynamically to a query that you may not have written? In that case whomever writes that query could transform your column of interest which would result in visibility over things you didn't intend, like:
select * from
(
select 'test' as col_a, launch_codes from table_a
) outer_table_a
where outer_table_a.col_a = 'test'
I'm having the following situation:
I've got a quite complex view from which I've to select a couple of records.
SELECT * FROM VW_Test INNER JOIN TBL_Test ON VW_Test.id = TBL_Test.id
WHERE VW_Test.id IN (1000,1001,1002,1003,1004,[etc])
This returns a result practically instantly (currently with 25 items in that IN statement). However when I use the following query it slows down really fast.
SELECT * FROM VW_Test INNER JOIN TBL_Test ON VW_Test.id = TBL_Test.id
WHERE VW_Test.id IN (SELECT id FROM TBL_Test)
With 25 records in the TBL_Test this query takes about 5 seconds. I've got an index on that id in the TBL_Test.
Anyone got an idea why this happens and how to get performance up?
EDIT: I forgot to mention that this subquery
SELECT id FROM TBL_Test
returns a result instantly as well.
Well, when using a subquery the database engine will first have to generate the results for the subquery before it can do anything else, which takes time. If you have a predefined list, this will not need to happen and the engine can simply use those values 'as is'. At least, this is how I understand it.
How to improve performance: do away with the subquery. I don't think you even need the IN clause in this case. The INNER JOIN should suffice.
Say I have a select statement that goes..
select * from animals
That gives a a query result of all the columns in the table.
Now, if the 42nd column of the table animals is is_parent, and I want to return that in my results, just after gender, so I can see it more easily. But I also want all the other columns.
select is_parent, * from animals
This returns ORA-00936: missing expression.
The same statement will work fine in Sybase, and I know that you need to add a table alias to the animals table to get it to work ( select is_parent, a.* from animals ani), but why must Oracle need a table alias to be able to work out the select?
Actually, it's easy to solve the original problem. You just have to qualify the *.
select is_parent, animals.* from animals;
should work just fine. Aliases for the table names also work.
There is no merit in doing this in production code. We should explicitly name the columns we want rather than using the SELECT * construct.
As for ad hoc querying, get yourself an IDE - SQL Developer, TOAD, PL/SQL Developer, etc - which allows us to manipulate queries and result sets without needing extensions to SQL.
Good question, I've often wondered this myself but have then accepted it as one of those things...
Similar problem is this:
sql>select geometrie.SDO_GTYPE from ngg_basiscomponent
ORA-00904: "GEOMETRIE"."SDO_GTYPE": invalid identifier
where geometrie is a column of type mdsys.sdo_geometry.
Add an alias and the thing works.
sql>select a.geometrie.SDO_GTYPE from ngg_basiscomponent a;
Lots of good answers so far on why select * shouldn't be used and they're all perfectly correct. However, don't think any of them answer the original question on why the particular syntax fails.
Sadly, I think the reason is... "because it doesn't".
I don't think it's anything to do with single-table vs. multi-table queries:
This works fine:
select *
from
person p inner join user u on u.person_id = p.person_id
But this fails:
select p.person_id, *
from
person p inner join user u on u.person_id = p.person_id
While this works:
select p.person_id, p.*, u.*
from
person p inner join user u on u.person_id = p.person_id
It might be some historical compatibility thing with 20-year old legacy code.
Another for the "buy why!!!" bucket, along with why can't you group by an alias?
The use case for the alias.* format is as follows
select parent.*, child.col
from parent join child on parent.parent_id = child.parent_id
That is, selecting all the columns from one table in a join, plus (optionally) one or more columns from other tables.
The fact that you can use it to select the same column twice is just a side-effect. There is no real point to selecting the same column twice and I don't think laziness is a real justification.
Select * in the real world is only dangerous when referring to columns by index number after retrieval rather than by name, the bigger problem is inefficiency when not all columns are required in the resultset (network traffic, cpu and memory load).
Of course if you're adding columns from other tables (as is the case in this example it can be dangerous as these tables may over time have columns with matching names, select *, x in that case would fail if a column x is added to the table that previously didn't have it.
why must Oracle need a table alias to be able to work out the select
Teradata is requiring the same. As both are quite old (maybe better call it mature :-) DBMSes this might be historical reasons.
My usual explanation is: an unqualified * means everything/all columns and the parser/optimizer is simply confused because you request more than everything.