SQL multiple tables join and pivot with column name and value - sql

I'm looking for a way to join two (sometimes more) tables.
I'll start with two and add as I get the pieces working.
Table1 has two columns that identify it
T1ContainerID
T1ObjectID
Table2 has similar columns but starts with T2 but the values will match
T2ContainerID
T2ObjectID
In Table2 there are two columns I am targeting
ObjectName
ObjectValue
There can be any number of ObjectName entries for a given record.
For instance one may have name, address,and a date
another may have Name, address,port,date,ServerName,Device,Status
What I need is a way to pivot all of the potential columns in Table2 in line with Table1 and is that value is not in Table2 for table1 then just make it NULL. I want the header of these columns to be the ObjectName and the value to be ObjectValue. If i can't get a wildcard to grab all potential values i can settle for just calling out each column manually. I was only hoping for a wildcard as it may change as different values for new records get added. Worst case i just adjust code to add anything new.
I do have a bunch of queries that rebuild the database every night and dump it into a different database but I'd like to have a query to pull the results from the main database to get current values rather than something that was run every morning.

Related

Selecting a large number of rows by index using SQL

I am trying to select a number of rows by the value of a column called ID. I know you can do this pretty easily by:
SELECT col1, col2, col3 FROM mytable WHERE id IN (1,2,3,4,5...)
However, what if there are a few million IDs I want to select and the IDs don't always have pattern (which means I can't use something like BETWEEN x AND y)? Does this select statement still work or is there better ways of doing so?
The actual application is this. Filters are specified by users, which is compared to some attributes of the records. From those filters, we create a subset of the data which is of interest to a particular user. There are about 30 million records each with roughly ~3000 attributes (which is stored in roughly 30 tables, but every table has ID as a primary key), so every time someone makes a query about their desired subset of records, we'd have to join many tables, apply those filters, and figure out what his subset looks like. In order to avoid joining many tables all the time, I thought maybe it's a better idea to join the tables once, figure out the id of the selected subset, and this way each time a new query is made, all we have to do is select the relevant columns of the rows that match the filtered ids.
This depends on the database and the interface you are using. For a few hundred or thousand values, no problem. But your question specifies millions. And that could start to get into limits on the length of the query -- either specified by the database, the tool you are using, or intermediate libraries.
If you have so many ids, I would strongly recommend that you load them into a table in the database with the id as the primary key. Then use join or exists to identify the rows in your table that match.
Often, such a list would be generated in the database anyway. In that case, you can use a subquery or CTE and just include that code in your final query.

How to update numerical column of one table based on matching string column from another table in SQL

I want to update numerical columns of one table based on matching string columns from another table.i.e.,
I have a table (let's say table1) with 100 records containing 5 string (or text) columns and 10 numerical columns. Now I have another table that has the same structure (columns) and 20 records. In this, few records contain updated data of table1 i.e., numerical columns values are updated for these records and rest are new (both text and numerical columns).
I want to update numerical columns for records with the same text columns (in table1) and insert new data from table2 into table1 where text columns are also new.
I thought of taking an intersect of these two tables and then update but couldn't figure out the logic as how can I update the numerical columns.
Note: I don't have any primary or unique key columns.
Please help here.
Thanks in advance.
The simplest solution would be to use two separate queries, such as:
UPDATE b
SET b.[NumericColumn] = a.[NumericColumn],
etc...
FROM [dbo].[SourceTable] a
JOIN [dbo].[DestinationTable] b
ON a.[StringColumn1] = b.[StringColumn1]
AND a.[StringColumn2] = b.[StringColumn2] etc...
INSERT INTO [dbo].[DestinationTable] (
[NumericColumn],
[StringColumn1],
[StringColumn2],
etc...
)
SELECT a.[NumericColumn],
a.[StringColumn1],
a.[StringColumn2],
etc...
FROM [dbo].[SourceTable] a
LEFT JOIN [dbo].[DestinationTable] b
ON a.[StringColumn1] = b.[StringColumn1]
AND a.[StringColumn2] = b.[StringColumn2] etc...
WHERE b.[NumericColumn] IS NULL
--assumes that [NumericColumn] is non-nullable.
--If there are no non-nullable columns then you
--will have to structure your query differently
This will be effective if you are working with a small dataset that does not change very frequently and you are not worried about high contention.
There are still a number of issues with this approach - most notably what happens if either the source or destination table is accessed and/or modified while the update statement is running. Some of these issues can be worked around other ways but so much depends on the context of how the tables are used that it is difficult to provide a more effective generically-applicable solution.

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

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.

Strange inserting problem

I am putting a table together with the following code:
create table temp
(pnum integer,
pnam varchar(30));
insert into temp(pnum)
select player_number
from players;
insert into temp(pnam)
select player_name
from positions;
It basically works except for the fact that, while both columns are preeent throughout the whole table, they are filled out sequentially. I want all the data from the second select to appear after the data from the first select ON THE SAME LINE. At present, I simply get a bunch of blank lines in the pnam column (while pnum fills out nicely), then get a bunch of blank lines in the pnum column (while pnam fills out nicely). IF anyone knows how to solve this, your prompt reply will be incredibly appreciated!
Yep - the problem is you're doing 2 discrete and seperate inserts, so SQL doesn't know that you want the numbers and the names to match up. You need to rewrite the Select statement into one.
Assuming that both the players and the positions table contains a filed called player_number, you can use this to tie the two tables together (if not, pick a unique field thats in both tables that ties the data together and use that.
insert into temp(pnum,pnam)
select player_number,player_name
from players inner join positions on players.player_number = positions.player_number
Things to note:
Line 1 - see how we are now inserting into both columns at the same time. This will give you the data layout you're looking for
Line 2 - see how we're selecting two bits of data to insert
Line 3 - this is where we join the two tables together (using player_number columnn from both). We need to join them together because in Line 2 we need to select one column from each.
Hope that makes sense. If not, shout. Also, maybe read up on inserting rows using INSERT and SELECT and using inner joins

SQL Server join and wildcards

I want to get the results of a left join between two tables, with both having a column of the same name, the column on which I join. The following query is seen as valid by the import/export wizard in SQL Server, but it always gives an error. I have some more conditions, so the size wouldn't be too much. We're using SQL Server 2000 iirc and since we're using an externally developed program to interact with the database (except for some information we can't retrieve that way), we can not simply change the column name.
SELECT table1.*, table2.*
FROM table1
LEFT JOIN table2 ON table1.samename = table2.samename
At least, I think the column name is the problem, or am I doing something else wrong?
Do more columns than just your join key have the same name? If only your join key has the same name then simply select one of them since the values will be equivalent except for the non-matching rows (which will be NULL). You will have to enumerate all your other columns from one of the tables though.
SELECT table2.samename,table1.othercolumns,table2.*
FROM table1
LEFT JOIN table2 ON table1.samename = table2.samename
You may need to explicitly list the columns from one of the tables (the one with less fields), and leave out the 2nd instance of what would be the duplicate field..
select Table1.*, {skip the field Table2.sameName} Table2.fld2, Table2.Fld3, Table2.Fld4... from
Since its a common column, it APPEARS its trying to create twice in the result set, thus choking your process.
Since you should never use select *, simply replace it with the column names of the columns you want. THe join column has the same value (or null) in both sides of the join, so only select one of themm the one from table1 which will always have the value.
If you want to select all the columns from both tables just use Select * instead of including the tables separately. That will however leave you with duplicate column names in the result set, so even reading them out by name will not work and reading them by index will give inconsistent results, as changing the columns in the database will change the resultset, breaking any code depending on the ordinals of the columns.
Unfortunately the best solution is to specify exactly the columns you need and create aliases for the duplicates so they are unique.
I quickly get the column headings by setting the query to text mode and copying the top row ...