How can I use record content from one table to update another, without a join option? - sql

I need to update values in a column in a specific table that exists in all our databases, but do not know the name of the column as it is user-generated.
I have two tables: one of them with user-generated columns tab_Case. In this table there is a column attachment that I need to update if the following condition applies: WHERE attachment = '0' (if true then the value needs to be changed to NULL).
In its simplest form the update query would look something like this:
UPDATE tab_Case
SET attachment = 'NULL'
WHERE attachment = '0'
This table is used in all our databases, so I need to write a query general enough to be usable across all of them.
The problem is that as the table uses user-generated columns, I have no way of knowing what the exact name is of concerned column-type, and exactly how many of those columns exist in the table.
I can, however, find out the type of the column by looking it up in another table tbl_itemPart inner joined with tbl_ValueType, like this:
SELECT ip.DbReference, ip.DbTableName, vt.ValueDescription
FROM tbl_itemPart ip
INNER JOIN tbl_ValueTypes vt ON ip.ValueTypeId = vt.ValuetypeId
WHERE vt.ValueDescription = 'file'
AND ip.DbTableName = 'tab_Case'
The columns I need are always of type 'file' and as the tab_Case table is referenced in tbl_ItemPart it is easy to find out 1) if any columns of type 'file' exist in this table, and 2) when true, what their respective names are.
So great, now I know the names of the columns that I need to potentially update. But, this is where I get lost: how do I use that information in my update query?
How do I write a script that first checks the tbl_itemPart for existence of any columns in tab_Case of type ' file', then retrieves the actual values (= names of those columns) from the DbReference column in tbl_itemPart and then finally uses those values in the update query for tab_Case?
Remember that this scripts needs to automatically do this for each of our databases, so I do not want to look up column names manually per database and then adjust my script accordingly for each of the databases.
I am very new to programming, and may be missing something very obvious, but so far I haven't been able to find a solution, or any relevant information to help me on my way.

Related

how can I link rows of a SQL table for some columns but not others?

I have a table of values in excel that I want to put into sql as a lookup table. the table looks like this:
the sql table looks like this:
having this in SQL, I now want to never use the excel file ever again.
I also need the ability to change the parameters, but some of them in the excel file were linked by merging the cells and thereby shared the same value, if it changed for one it changed for all.
for example: when I change Parameter B for Product 1, I need it to change it for Products 2, 3, 4, and 5 because they share the same cell in the excel table. And if I change parameter A for Product 2, It only changes for product 2 and 3. I am looking for a SQL Query solution. I have the ability to change the table structure as well.
Here goes my example query:
Update [Table] Set [Parameter_A] = '{new_parameter_tag}'
Where [product] = '{selected_product_tag}'
except I want to have the Where include all the rows that share the same cell from the excel table.
I want to be able to update the SQL table for multiple products at a time based on if they share the same cell for that parameter in the excel file.
here is my initial guess at an answer:
Select [{Parameter}],[Product],[Extra_column]
From [Table]
Where [Product] = '{selected_product}'
this returns one row and [Extra_column] that contains a grouping number shared by others in the same cell grouping. this then gets stored as {Extra_column}. then:
Update [Table] Set [{Parameter}] = '{new_parameter_value}'
Where [product] = '{selected_product}' Or [Extra_column] = '{Extra_Column}'
this requires two queries and also means that i need twice as many columns as i had before. I am looking for something a little more elegant.
This is SQL Server 2012 and the {} indicate a value that I am passing in form a script.
I ended up doing something similar to what I had above, the user enters the group they want to edit (it's pretty easy to pick out which one you want when viewing the table) as:
Update [table]
Set [{Parameter}]={NewValue}
Where [Extra_Column] = '{Extra_Column}'
I had to add three columns for the grouping indexes but over 43 parameters that doesn't add much to my table size. I did not take into account the fact that if I change a single parameter for a single product that would remove it from the "group" essentially for just that parameter, and later I would overwrite the changed value if I do a group change for that parameter. I could add in a check to only change values that match within that group but either way the user will have to be smart about what they do. luckily, they can see the table before they change it.

How to update a field in a table basing on a field from another table

So I have two tables, InTheMiddle and Table2.
The 1st one contains Name column, the 2nd one contains ID and Name columns.
(they also have other columns, but irrelevant to this question)
I want to update/change the names in the 1st table with the IDs from the second one, but of course only when the names match and there's only one name (so there aren't any semicolons ";").
Here's a query that I tried to use, but Access tells me "Operation must use an updateable query"
UPDATE InTheMiddle
SET [Name] =
(SELECT [Table2].ID
FROM [Table2]
WHERE InTheMiddle.[Name] = [Table2].[Name]
AND InTheMiddle.[Name] NOT LIKE "*;*"
);
Possible duplicate to Operation must use an updatable query. (Error 3073) Microsoft Access, in which the accepted answer suggests that the only way to avoid that error message is to use temporary tables.
Besides the accepted answer, this answer suggests a workaround to code looking like yours

T-SQL - Using Column Name in where condition without any references when having multiple tables that are engaged using multiple joins

I am a newbie for T-Sql, I came across a SP where multiple tables are engaged using multiple joins but the where clause contain a column field without any table reference and assigned for an incoming variable,like
where 'UserId = #UserId'
instead - no table reference like
'a.UserId = #Userid'`
Can any please do refer to me any material that clears my mind regarding such issue.
If the query works it means that there is only one Column with the name UserId, if there are multiple columns with the same name you have to reference the table too.
If you don't specify the table reference you will get
Ambiguous column name 'UserId'. error
Which means there are more then 2 tables with a column name UserId.
Anyway, always try and use the reference table.

How to select all fields in SQL joins without getting duplicate columns names?

Suppose I have one table A, with 10 fields. And Table B, with 5 fields.
B links to A via a column named "key", that exists both in A, and in B, with the same name ("key").
I am generating a generic piece of SQL, that queries from a main table A, and receives a table name parameter to join to, and select all A fields + B.
In this case, I will get all the 15 fields I want, or more precisely - 16, because I get "key" twice, once from A and once from B.
What I want is to get only 15 fields (all fields from the main table + the ones existing in the generic table), without getting "key" twice.
Of course I can explicit the fields I want in the SELECT itself, but that thwarts my very objective of building a generic SQL.
It really depends on which RDBMS you're using it against, and how you're assembling your dynamic SQL. For instance, if you're using Oracle and it's a PL/SQL procedure putting together your SQL, you're presumably querying USER_TAB_COLS or something like that. In that case, you could get your final list of columns names like
SELECT DISTINCT(column_name)
FROM user_tab_cols
WHERE table_name IN ('tableA', 'tableB');
but basically, we're going to need to know a lot more about how you're building your dynamic SQL.
Re-thinking about what I asked makes me conclude that this is not plausible. Selecting columns in a SELECT statement picks the columns we are interested in from the list of tables provided. In cases where the same column name exists in more than one of the tables involved, which are the cases my question is addressing, it would, ideally, be nice if the DB engine could return a unique list of fields - BUT - for that it would have to decide itself which column (and from which table) to choose, from all the matches - which is something that the DB cannot do, because it is solely dependent in the user's choice.

How not to display columns which are NULL in a view

I've set up a view which combines all the data across several tables. Is there a way to write this so that only columns which contain non-null data are displayed, and those columns which contain all NULL values are not included?
ADDED:
Sorry, still studying and working on my first big project so every day seems to be a new experience at the minute. I haven't been very clear, and that's partly because I'm not sure I'm going about things the right way! The client is an academic library, and the database records details of specific collections. The view I mentioned is to display all the data held about an item, so it is bringing together tables on publication, copy, author, publisher, language and so on. A small number of items in the collection are papers, so have additional details over and above the standard bibliographic details. What I didn't want was a user to get all the empty fields relating to papers if what was returned only consisted of books, therefore the paper table fields were all null. So I thought perhaps there would be a way to not show these. Someone has commented that this is the job of the client application rather than the database itself, so I can leave this until I get to that phase of the project.
There is no way to do this in sql.
CREATE VIEW dbo.YourView
AS
SELECT (list of fields)
FROM dbo.Table1 t1
INNER JOIN dbo.Table2 t2 ON t1.ID = t2.FK_ID
WHERE t1.SomeColumn IS NOT NULL
AND t2.SomeOtherColumn IS NOT NULL
In your view definition, you can include WHERE conditions which can exclude rows that have certain columns that are NULL.
Update: you cannot really filter out columns - you define the list of columns that are part of your view in your view definition, and this list is fixed and cannot be dynamically changed......
What you might be able to do is us a ISNULL(column, '') construct to replace those NULLs with an empty string. Or then you need to handle excluding those columns in your display front end - not in the SQL view definition...
The only thing I see you could do is make sure to select only those columns from the view that you know aren't NULL:
SELECT (list of non-null fields) FROM dbo.YourView
WHERE (column1 IS NOT NULL)
and so forth - but there's no simple or magic way to select all columns that aren't NULL in one SELECT statement...
You cannot do this in a view, but you can do it fairly easily using dynamic SQL in a stored procedure.
Of course, having a schema which shifts is not necessarily good for clients who consume the data, but it can be efficient if you have very sparse data AND the consuming client understands the varying schema.
If you have to have a view, you can put a "header" row in your view which you can inspect client-side on the first row in your loop to see if you want to not bother with the column in your grid or whatever, you can do something like this:
SELECT * FROM (
-- This is the view code
SELECT 'data' as typ
,int_col
,varchar_col
FROM TABLE
UNION ALL
SELECT 'hdr' as typ
-- note that different types have to be handled differently
,CASE WHEN COUNT(int_col) = 0 THEN NULL ELSE 0 END
,CASE WHEN COUNT(varchar_col) = 0 THEN NULL ELSE '' END
FROM TABLE
) AS X
-- have to get header row first
ORDER BY typ DESC -- add other sort criteria here
If we're reading your question right, there won't be a way to do this in SQL. The output of a view must be a relation - in (over-)simplified terms, it must be rectangular. That is, each row must have the same number of columns.
If you can tell us more about your data and give us some idea of what you want to do with the output, we can perhaps offer more positive suggestions.
In general, add a WHERE clause to your query, e.g.
WHERE a IS NOT NULL AND b IS NOT NULL AND c IS NOT NULL
Here, a b c are your column names.
If you are joining tables together on potentially NULL columns, then use an INNER JOIN, and NULL values will not be included.
EDIT: I may have misunderstood - the above filters out rows, but you may be asking to filter out columns, e.g. you have several columns and you only want to display columns that contain at least one null value across all the rows you are returning. Using dynamic SQL offers a solution, since the set columns varies depending upon your data.
Here's a SQL query that builds another SQL query containing the appropriate columns. You could run this query, and then submit it's result as another query. It assumes 'pk' is some column that is always non-null, e.g. a primary key - this means we can prefix additional row names with a comma.
SELECT CONCAT("SELECT pk"
CASE (count(columnA)) WHEN 0 THEN '' ELSE ',columnA' END,
CASE (count(columnB)) WHEN 0 THEN '' ELSE ',columnB' END,
// etc..
' FROM (YourQuery) base')
FROM
(YourQuery) As base
The query works using Count(column) - the aggregate function ignores NULL values, and so returns 0 for a column consisting entirely of NULLs. The query builder assumes that YourQuery uses aliases to ensure there no duplicate column names.
While you cant put this into a view, you could wrap it up as a stored procedure that copies the data to another table - the result table. You may also set up a trigger so that the result table is updated whenever the base tables change.
I suspect what's going on is that an end user is running CrystalReports and complaining about all the empty columns that have to be removed manually.
It would actually be possible to create a stored procedure that would create a view on the fly, leaving out dataless columns. But then you would have to run this proc before using the view.
Is that acceptable?