SQL Server New column added to table but problems with Select * - sql

Morning,
I have a stored procedure that returns 'SELECT *' from a table.
Whenever I add a new column to the table, the 'SELECT *' often returns some data in the wrong columns.
Is this an optimization or caching problem? How do I solve this without having to explicitly define the return column names in my stored procedure?
Thanks!

Regardless of the exact nature of your problem, or a solution to it, I would recommend that you don't use Select * From Table. This is less efficient - each time you run the query, an extra request is sent to the DB to determine exactly what columns '*' constitutes, and then a proper request is sent with specific column information.

The reason for your problem probably depends on the client stack you're using.
Speaking in very general terms, SQL Server will return the columns in the order they're added to the table if you perform a SELECT *. If there is more than one table involved in the query, it will return the columns from each table in the order they appear in the query.
Neither caching nor optimisation should affect this server-side if the table columns have changed, so it may be something happening between your code and the server, in whatever data access stack you happen to be using.
This is one of the reasons it's generally recommended not to use "SELECT *" in client code.

The best way to avoid this problem is to have the stored procedure return a predefined set of columns (SELECT a, b instead of SELECT *) and use a table join to retrieve the rest of the code. Because stored procedures cannot be part of a query, you could refactor the stored procedure into a table-valued user-defined function and perform a join on it:
SELECT f.a, f.b, t.*
FROM dbo.fn_YourFunction('a', 'b') f
INNER JOIN YourTable t ON f.id = t.id

Related

Difference between two tables, unknown fields

Is there a way in Access using SQL to get the difference between 2 tables?
I'm building an audit function and I want to return all records from table1 where a value (or values) doesn't match the corresponding record in table2. Primary keys will always match between the two tables. They will always contain the exact same number of fields, field names, and types, as each other. However, the number and name of those fields cannot be determined before the query is run.
Please also note, I am looking for an Access SQL solution. I know how to solve this with VBA.
Thanks,
There are several possibilities to compare fields with known names, but there is no way in SQL to access fields without knowing their name. Mostly becase SQL doesn't consider fields to have a specific order in a table.
So the only way to accomplish what you need in pure Access-SQL would be, if there was a SQL-Command for it (kind of like the * as placeholder for all fields). But there isn't. Microsoft Access SQL Reference.
What you COULD do is create an SQL-clause on the fly in VBA. (I know, you said you didn't want to do it in VBA - but this is doing it in SQL, but using VBA to create the SQL..).
Doing everything in VBA would probably take some time, but creating an SQL on the fly is very fast and you can optimize it to the specific table. Then executing the SQL is the fastest solution you can get.
Not sure without your table structure but you can probably get that done using NOT IN operator (OR) using WHERE NOT EXISTS like
select * from table1
where some_field not in (select some_other_field from table2);
(OR)
select * from table1 t1
where not exists (select 1 from table2 where some_other_field = t1.some_field);
SELECT A.*, B.* FROM A FULL JOIN B ON (A.C = B.C) WHERE A.C IS NULL OR B.C IS NULL;
IF you have tables A and B, both with colum C, here are the records, which are present in table A but not in B.To get all the differences with a single query, a full join must be used,like above

PostgreSQL return select results AND add them to temporary table?

I want to select a set of rows and return them to the client, but I would also like to insert just the primary keys (integer id) from the result set into a temporary table for use in later joins in the same transaction.
This is for sync, where subsequent queries tend to involve a join on the results from earlier queries.
What's the most efficient way to do this?
I'm reticent to execute the query twice, although it may well be fast if it was added to the query cache. An alternative is store the entire result set into the temporary table and then select from the temporary afterward. That also seems wasteful (I only need the integer id in the temp table.) I'd be happy if there was a SELECT INTO TEMP that also returned the results.
Currently the technique used is construct an array of the integer ids in the client side and use that in subsequent queries with IN. I'm hoping for something more efficient.
I'm guessing it could be done with stored procedures? But is there a way without that?
I think you can do this with a Postgres feature that allows data modification steps in CTEs. The more typical reason to use this feature is, say, to delete records for a table and then insert them into a log table. However, it can be adapted to this purpose. Here is one possible method (I don't have Postgres on hand to test this):
with q as (
<your query here>
),
t as (
insert into temptable(pk)
select pk
from q
)
select *
from q;
Usually, you use the returning clause with the data modification queries in order to capture the data being modified.

Selecting from two non-related tables at the same time

Suppose I have a table with lots of rows and columns (alias: bigtable), and a table that always has 1 row, but multiple columns (alias: 1rowtable). The 1rowtable has nothing to do with bigtable, it is just there for some settings my script uses that are modified dynamically. So I cannot use static SQLCMD variables for that and I cannot use normal variables for that either because my script has GO statements.
Now I want to write a select statement that accesses BOTH tables.
If I do:
SELECT ... FROM bigtable, 1rowtable
it does a CROSS JOIN so that is bad, can't go that route.
If I use a CTE for 1rowtable, I have to access its fields with
SELECT field FROM 1rowtable
So that is bad too. Same with a table valued function like:
CREATE FUNCTION getSetting(#name nvarchar(40))
RETURNS TABLE
AS
RETURN (SELECT name FROM 1rowtable WHERE name = #name)
Obviously I cannot use a scalar function at all because it only returns a specific datatype, but the settings have different datatypes. Yet, obviously I would like to use it LIKE a scalar function of course without doing the 'SELECT .. FROM dbo.getfieldfrom1rowtable(..)' stuff, since I am using the 1rowtable rather often in queries.
I also tried doing:
SELECT
(SELECT
<expression involving bigtable and 1rowtable>,
<expression involving bigtable and 1rowtable>,
<expression involving bigtable and 1rowtable>,
...
FROM 1rowtable)
FROM bigtable
But of course a subselect cannot select more than one item if it does not begin with exists...
So what should I do? It seems I will have to continue using 'SELECT .. FROM dbo.getfieldfrom1rowtable(..)' every time? Just curious :)
PS. ms sql server 2008r2
There is nothing wrong with using a cross join to bring together rows from tables, particularly when one only has one row.
Use the syntax:
select bt.*, ort.*
from bigtable bt cross join
onerowtable ort
There is nothing inherently "wrong" with cross joins, when they are used correctly. The problem is when they are used inadvertently. If you cross join two tables with a million rows . . . well, your temp space is going to fill up, your processor(s) will be very busy, and the query will eventually crash due to a lack of resources.
However, cross joining a table with one row to another table poses no problems at all.

Simple query for generating database metrics?

Give a database (Sybase) with many tables, I would like to write a SQL query that will calculate, for each table, the number of rows and the number of columns.
Unfortunately, my SQL is a bit rusty. I can generate the table names:
select name from sysobjects where type = 'U'
but how to bind the databases returned to T in:
select count(*) from T
is beyond me. Is it even possible to do this kind of thing?
I don't use Sybase, but the online docs indicate the row counts are in systabstats and the columns are in syscolumns.
SELECT sysobjects.name,
(SELECT COUNT(*) FROM syscolumns WHERE syscolumns.id = sysobjects.id) AS cols,
systabstats.rowcnt
FROM sysobjects
JOIN systabstats
ON (sysobjects.id = systabstats.id AND sysobjects.type = 'U' AND systabstats.indid = 0)
As fredt has given the answer, I'll just provide some extra info.
The built in procedure sp_spaceused "tablename" will give you the number of rows for a selected table, along with details of how much storage space it's using. Used without the parameter it provides storage usage for the current database as a whole.
You can look at the SQL in the various system stored procedures to see where they get their information from. sp_spaceused and sp_help would both be useful for you in this. They live in the sybsystemprocs database. Just be careful not to modify any of those procedures.
There are various versions of a stored procedure called sp_rowcount floating around the internet, that provide what you ask for (rowcount anyway), but inside they are equivalent to the select statement from fredt. The one I use provides index count and table locking scheme. I don't recall exactly where I got mine so don't want to just distribute it in case I upset someone's copyright.

Use SELECT inside an UPDATE query

How can I UPDATE a field of a table with the result of a SELECT query in Microsoft Access 2007.
Here's the Select Query:
SELECT Min(TAX.Tax_Code) AS MinOfTax_Code
FROM TAX, FUNCTIONS
WHERE (((FUNCTIONS.Func_Pure)<=[Tax_ToPrice]) AND ((FUNCTIONS.Func_Year)=[Tax_Year]))
GROUP BY FUNCTIONS.Func_ID;
And here's the Update Query:
UPDATE FUNCTIONS
SET FUNCTIONS.Func_TaxRef = [Result of Select query]
Well, it looks like Access can't do aggregates in UPDATE queries. But it can do aggregates in SELECT queries. So create a query with a definition like:
SELECT func_id, min(tax_code) as MinOfTax_Code
FROM Functions
INNER JOIN Tax
ON (Functions.Func_Year = Tax.Tax_Year)
AND (Functions.Func_Pure <= Tax.Tax_ToPrice)
GROUP BY Func_Id
And save it as YourQuery. Now we have to work around another Access restriction. UPDATE queries can't operate on queries, but they can operate on multiple tables. So let's turn the query into a table with a Make Table query:
SELECT YourQuery.*
INTO MinOfTax_Code
FROM YourQuery
This stores the content of the view in a table called MinOfTax_Code. Now you can do an UPDATE query:
UPDATE MinOfTax_Code
INNER JOIN Functions ON MinOfTax_Code.func_id = Functions.Func_ID
SET Functions.Func_TaxRef = [MinOfTax_Code].[MinOfTax_Code]
Doing SQL in Access is a bit of a stretch, I'd look into Sql Server Express Edition for your project!
I wrote about some of the limitations of correlated subqueries in Access/JET SQL a while back, and noted the syntax for joining multiple tables for SQL UPDATEs. Based on that info and some quick testing, I don't believe there's any way to do what you want with Access/JET in a single SQL UPDATE statement. If you could, the statement would read something like this:
UPDATE FUNCTIONS A
INNER JOIN (
SELECT AA.Func_ID, Min(BB.Tax_Code) AS MinOfTax_Code
FROM TAX BB, FUNCTIONS AA
WHERE AA.Func_Pure<=BB.Tax_ToPrice AND AA.Func_Year= BB.Tax_Year
GROUP BY AA.Func_ID
) B
ON B.Func_ID = A.Func_ID
SET A.Func_TaxRef = B.MinOfTax_Code
Alternatively, Access/JET will sometimes let you get away with saving a subquery as a separate query and then joining it in the UPDATE statement in a more traditional way. So, for instance, if we saved the SELECT subquery above as a separate query named FUNCTIONS_TAX, then the UPDATE statement would be:
UPDATE FUNCTIONS
INNER JOIN FUNCTIONS_TAX
ON FUNCTIONS.Func_ID = FUNCTIONS_TAX.Func_ID
SET FUNCTIONS.Func_TaxRef = FUNCTIONS_TAX.MinOfTax_Code
However, this still doesn't work.
I believe the only way you will make this work is to move the selection and aggregation of the minimum Tax_Code value out-of-band. You could do this with a VBA function, or more easily using the Access DLookup function. Save the GROUP BY subquery above to a separate query named FUNCTIONS_TAX and rewrite the UPDATE statement as:
UPDATE FUNCTIONS
SET Func_TaxRef = DLookup(
"MinOfTax_Code",
"FUNCTIONS_TAX",
"Func_ID = '" & Func_ID & "'"
)
Note that the DLookup function prevents this query from being used outside of Access, for instance via JET OLEDB. Also, the performance of this approach can be pretty terrible depending on how many rows you're targeting, as the subquery is being executed for each FUNCTIONS row (because, of course, it is no longer correlated, which is the whole point in order for it to work).
Good luck!
I had a similar problem. I wanted to find a string in one column and put that value in another column in the same table. The select statement below finds the text inside the parens.
When I created the query in Access I selected all fields. On the SQL view for that query, I replaced the mytable.myfield for the field I wanted to have the value from inside the parens with
SELECT Left(Right(OtherField,Len(OtherField)-InStr((OtherField),"(")),
Len(Right(OtherField,Len(OtherField)-InStr((OtherField),"(")))-1)
I ran a make table query. The make table query has all the fields with the above substitution and ends with INTO NameofNewTable FROM mytable
Does this work? Untested but should get the point across.
UPDATE FUNCTIONS
SET Func_TaxRef =
(
SELECT Min(TAX.Tax_Code) AS MinOfTax_Code
FROM TAX, FUNCTIONS F1
WHERE F1.Func_Pure <= [Tax_ToPrice]
AND F1.Func_Year=[Tax_Year]
AND F1.Func_ID = FUNCTIONS.Func_ID
GROUP BY F1.Func_ID;
)
Basically for each row in FUNCTIONS, the subquery determines the minimum current tax code and sets FUNCTIONS.Func_TaxRef to that value. This is assuming that FUNCTIONS.Func_ID is a Primary or Unique key.
I did want to add one more answer that utilizes a VBA function, but it does get the job done in one SQL statement. Though, it can be slow.
UPDATE FUNCTIONS
SET FUNCTIONS.Func_TaxRef = DLookUp("MinOfTax_Code", "SELECT
FUNCTIONS.Func_ID,Min(TAX.Tax_Code) AS MinOfTax_Code
FROM TAX, FUNCTIONS
WHERE (((FUNCTIONS.Func_Pure)<=[Tax_ToPrice]) AND ((FUNCTIONS.Func_Year)=[Tax_Year]))
GROUP BY FUNCTIONS.Func_ID;", "FUNCTIONS.Func_ID=" & Func_ID)
I know this topic is old, but I thought I could add something to it.
I could not make an Update with Select query work using SQL in MS Access 2010. I used Tomalak's suggestion to make this work. I had a screenshot, but am apparently too much of a newb on this site to be able to post it.
I was able to do this using the Query Design tool, but even as I was looking at a confirmed successful update query, Access was not able to show me the SQL that made it happen. So I could not make this work with SQL code alone.
I created and saved my select query as a separate query. In the Query Design tool, I added the table I'm trying to update the the select query I had saved (I put the unique key in the select query so it had a link between them). Just as Tomalak had suggested, I changed the Query Type to Update. I then just had to choose the fields (and designate the table) I was trying to update. In the "Update To" fields, I typed in the name of the fields from the select query I had brought in.
This format was successful and updated the original table.