Relating 2 columns in a database - sql-server

I can't find a way to call the database and ask for it to return specific entries.
I have a database called "Barrios" and another called "Localidades."
"Barrios" has 3 columns: Id (pk, int), Localidad (Fk, int), Barrio (varchar(50))
"Localidades" has 2: Id (PK, int) and Zona (varchar(50))
In "Localidades" I have the states, and in the Barrios I have the neighborhoods.
How do I format my database so that when someone inserts a neighborhood, the associated state is populated as well?

You could use a function in combination with an expression for the computed column?
SQL Server computed column select from another table

select * from Barrios inner join Localidades on Barrios.Localidad = Localidades.Id where Localidades.Id = 1
thats the sentence, i just made it :)

Related

Can table columns be created by copying the datatype from another column ? (for ex like %type in Oracle)

For example, this is possible in Oracle. I wanted to know if snowflake has a similar concept.
CREATE TABLE Purchases
(
purchase_date calendar.date%type,
customer_nr customer.customer_nr%type,
purchase_amount numeric(10,2)
)
I'm afraid there's no way to do that right now. You can use system$typeof to check for a column type, but that can't be used in a create table statement.
The referenceability that you have in your example is not available. You can build a table by joining one or more tables and/or views together and build the column list with columns from any of the joins and any that you explicitly add to the list. The key is to join on 1 = 2 or FALSE
Example
CREATE OR REPLACE TEMP TABLE TMP_X
AS
SELECT A."name" AS NAME
,A."owner" AS OWNER
,B.STG_ARRAY
,NULL::NUMERIC(10,2) AS PURCHASE_AMOUNT
,NULL AS COMMENT
FROM TABLE_A A
JOIN TABLE_B B
ON 1 = 2
;
NAME - takes datatype from A."name" column
OWNER - takes datatype from A."owner" column
STG_ARRAY - takes datatype from B.STG_ARRAY column
PURCHASE_AMOUNT - takes the datatype explicitly specified NUMERIC(10,2)
COMMENT - no explicit datatype -- takes default datatype of VARCHAR(16777216)

Understanding an ambiguous column name for inner query

I ran into a weird query today that I thought would be failed, but it succeeded in an unexpected way. Here's a minimal reproduction of it.
Tables and data:
CREATE TABLE Employee(ID int, Name varchar(max))
CREATE TABLE Engineer(ID int, Title varchar(max))
GO
INSERT INTO Employee(ID, Name) VALUES (1, 'Bobby')
INSERT INTO Employee(ID, Name) VALUES (2, 'Sue')
INSERT INTO Engineer(ID, Title) VALUES (1, 'Electrical Engineer')
INSERT INTO Engineer(ID, Title) VALUES (2, 'Network Engineer')
Queries:
--Find all Engineers with same title as Bobby has
SELECT * FROM Engineer WHERE Title IN (select Title from Employee WHERE Name = 'Bobby')
This returns all rows in Engineer table (unexpected, I thought it would fail). Note that the above query is incorrect. The inner query uses a column "Title" which doesn't exist in the table being selected from ("Employee"). So it must be binding the Title column value from Engineer in the outer query....which is always equal to itself so all rows are returned I think.
I can force it too if I fully qualify the column name, and that would fail as expected:
SELECT * FROM Engineer WHERE Title IN
(select Empl.Title from Employee Empl WHERE Name = 'Bobby')
This fails with "Invalid column name 'Title'."
Apparently if I were to add the Title column to the Employee table, it uses the Employee.Title column value instead.
ALTER TABLE Employee ADD Title varchar(max)
GO
UPDATE Employee SET Title = 'Electrical Engineer' WHERE ID = 1
UPDATE Employee SET Title = 'Network Engineer' WHERE ID = 2
SELECT * FROM Engineer WHERE Title IN
(select Title from Employee WHERE Name = 'Bobby')
This returns just one row (as expected).
I kind of understand what is happening here, what I'm looking for is a link to some documentation or some keyword that would help me read up and understand it fully (or even some explanation).
Of course it fails. There is no column named Title in your Employee table. In the query that does work it is a subquery so it is pulling Title from Engineer.
You can avoid this entirely if you develop the habit of ALWAYS referencing columns with 2 part naming instead of just the column name.
But in your queries you should start learning how to use joins instead of subqueries for everything. Your code would be far less confusing.
Since Title is not qualified it uses the Title from table Engineer
SELECT * FROM Engineer WHERE Title IN (select Title from Employee WHERE Name = 'Bobby')
In the last it uses the closest Title (from Employee) .
If you use alias and 2 part name then you stay out of this confusion.
As far as documentation. Finding closest column is probably an undocumented feature.
I found the documentation on the behavior: Qualifying Column Names in Subqueries
The general rule is that column names in a statement are implicitly qualified by the table referenced in the FROM clause at the same level. If a column does not exist in the table referenced in the FROM clause of a subquery, it is implicitly qualified by the table referenced in the FROM clause of the outer query.

Select from two different tables and store calculated value in a newly created table (Microsoft SQL Server 2014)

What would be the best way to take values from two different tables like 1st table has the value of Price, where 2nd table has the value of Quantity, and I will multiply Price by Quantity and the calculated values, Total_Price which will be store in table 3 (newly created). At 1st I've tried using FUNCTION, but many error pops out, so I change it to CTE. But my teacher suggest me to not use temporary tables, because when new row data is added to the tables, we need to run the CTE again to update it everytime new record is added. Is there any other method? Thank you.
You can try something like (syntax not verified!):
INSERT INTO Table_3 (Cur_Date,Prod,Qty,Total_Price)
VALUES (GETDATE() ,
<the passed product_ID> ,
<the passed quantity> ,
(SELECT (A.Quantity * B.Price)
FROM Table_1 A ,
Table_2 B
WHERE A.Product = <Your passed product ID>
AND A.Product = B.Product
)
);
The actual phrasing will depend on your DBMS.

Merge query using two tables in SQL server 2012

I am very new to SQL and SQL server, would appreciate any help with the following problem.
I am trying to update a share price table with new prices.
The table has three columns: share code, date, price.
The share code + date = PK
As you can imagine, if you have thousands of share codes and 10 years' data for each, the table can get very big. So I have created a separate table called a share ID table, and use a share ID instead in the first table (I was reliably informed this would speed up the query, as searching by integer is faster than string).
So, to summarise, I have two tables as follows:
Table 1 = Share_code_ID (int), Date, Price
Table 2 = Share_code_ID (int), Share_name (string)
So let's say I want to update the table/s with today's price for share ZZZ. I need to:
Look for the Share_code_ID corresponding to 'ZZZ' in table 2
If it is found, update table 1 with the new price for that date, using the Share_code_ID I just found
If the Share_code_ID is not found, update both tables
Let's ignore for now how the Share_code_ID is generated for a new code, I'll worry about that later.
I'm trying to use a merge query loosely based on the following structure, but have no idea what I am doing:
MERGE INTO [Table 1]
USING (VALUES (1,23-May-2013,1000)) AS SOURCE (Share_code_ID,Date,Price)
{ SEEMS LIKE THERE SHOULD BE AN INNER JOIN HERE OR SOMETHING }
ON Table 2 = 'ZZZ'
WHEN MATCHED THEN UPDATE SET Table 1.Price = 1000
WHEN NOT MATCHED THEN INSERT { TO BOTH TABLES }
Any help would be appreciated.
http://msdn.microsoft.com/library/bb510625(v=sql.100).aspx
You use Table1 for target table and Table2 for source table
You want to do action, when given ID is not found in Table2 - in the source table
In the documentation, that you had read already, that corresponds to the clause
WHEN NOT MATCHED BY SOURCE ... THEN <merge_matched>
and the latter corresponds to
<merge_matched>::=
{ UPDATE SET <set_clause> | DELETE }
Ergo, you cannot insert into source-table there.
You could use triggers for auto-insertion, when you insert something in Table1, but that will not be able to insert proper Shared_Name - trigger just won't know it.
So you have two options i guess.
1) make T-SQL code block - look for Stored Procedures. I think there also is a construct to execute anonymous code block in MS SQ, like EXECUTE BLOCK command in Firebird SQL Server, but i don't know it for sure.
2) create updatable SQL VIEW, joining Table1 and Table2 to show last most current date, so that when you insert a row in this view the view's on-insert trigger would actually insert rows to both tables. And when you would update the data in the view, the on-update trigger would modify the data.

TSQL: getting next available ID

Using SQL Server 2008, have three tables, table a, table b and table c.
All have an ID column, but for table a and b the ID column is an identity integer, for table c the ID column is a varchar type
Currently a stored procedure take a name param, following certain logic, insert to table a or table b, get the identity, prefix with 'A' or 'B' then insert to table c.
Problem is, table C ID column potentially have the duplicated values, i.e. if identity from table A is 2, there might already have 'A2','A3','A5' in the ID column for table C, how to write a T-SQL query to identify the next available value in table C then ensure to update table A/B accordingly?
[Update]
this is the current step,
1. depends on input parameter, insert to table A or table B
2. initialize seed value = ##Identity
3. calculate ID value to insert to table C by prefix 'A' or append 'B' with the seed value
4. look for record match in table C by ID value from step 3, if didn't find any record, insert it, else increase seed value by 1 then repeat step 3
The issue being at a certain value range, there could be a huge block of value exists in table C ID, i.e. A3000 to A500000 existed now in table C ID, the database query is extemely slow if follow the existing logic. Needs to figure out a logic to smartly get the minimum available number (without the prefix)
it is hard to describe, hope this make more sense, I truly appreciate any help on this Thanks in advance!
This should do the trick. Simple self extracting example will work in SSMS. I even made it out of order just in case. You would just change your table to be where #Data is and then change Identifier field to replace 'ID'.
declare #Data Table ( Id varchar(3) );
insert into #Data values ('A5'),('A2'),('B1'),('A3'),('B2'),('A4'),('A1'),('A6');
With a as
(
Select
ID
, cast(right(Id, len(Id)-1) as int) as Pos
, left(Id, 1) as TableFrom
from #Data
)
select
TableFrom
, max(Pos) + 1 as NextNumberUp
from a
group by TableFrom
EDIT: If you want to not worry about production data you could add this last part amending what I wrote:
Select
TableFrom
, max(Pos) as LastPos
into #Temp
from a
group by TableFrom
select TableFrom, LastPos + 1
from #Temp
Regardless if this was production environment you are going to have to hit part of it at some time to get data. If the datasets are not too large and just varchar(256) or less and only 5 million rows or less you could dump that entire column from tableC to a temp table. Honestly query performance versus imports change vastly from system to system.
Following your design there shouldn't be any duplicates in Table C considering that A and B are unique.
A | B | C
1 1 A1
2 2 A2
B1
B2

Resources