I have the following setup in SQL Server 2016. I want to insert into table B name, surname, address into there respective columns, but from the 3 columns in View A for employment, I want to insert a single row for each person based on their Employment into Employment Status column in Table B, What is the best way to do this?
View A
Name (String)
Surname (Sring)
Address (String)
Employed (boolean)
Non-Employed (boolean)
Retired (boolean)
Table B
Name (String)
Surname (Sring)
Address (String)
Employed Status (String)
Although you have three flags that seem exclusive, I see no reason to think that they actually are (unless you have some sort of validation).
So, I would concatenate the statuses together:
insert into b (name, surname, address, employed_status)
select name, surname, address,
stuff(concat(case when employeed = 1 then ', employed' else '' end,
case when non_employeed = 1 then ',non_employed' else '' end,
case when retired = 1 then ',retired' else '' end
), 1, 1, ''
)
from a;
Note: SQL Server does not have a boolean type, so I assume you are using 0/1 encoding for the columns.
I would take a step back and create another table called EmploymentState, into which I would add three rows "1 - Employed", "2 - Unemployed", "3 - Retired". Then add a foreign key to that table from Table A and Table B.
Unless of course, a single person can be in more than one state...in which case you need an intersection table. See https://www.bing.com/search?q=sql+intersection+table&qs=n&form=QBRE&sp=-1&ghc=1&pq=sql+intersection+tab&sc=0-20&sk=&cvid=153E23C3D25F461E89F71E106FBF7D66
Related
I have a question about SQL. I have created a table in SQL with only one column containing the name of two people (say John and Matt). Later I added a new column into the table with ALTER TABLE. This column will contain the surname of these people.
My question is, in case mmy table contained several people already is there a command to enter the surnames for all the people at once rather than writing one command for each person as in:
INSERT INTO table (Surname) VALUE (John's surname) and
INSERT INTO table (Surname) VALUE (Matt's surname) ?
Thanks in advance
P.D.
I tried something like:
UPDATE foo set Surname=("Parker","Walker") where Name =("John","Matt") but does not work
You want an update. Something like this:
update t
set surname = 'John'' surname'
where firstname = 'John';
You can do this separately for each name. Or use a case expression for multiple ones:
UPDATE foo
SET Surname = (CASE WHEN Name = 'John' THEN 'Parker'
WHEN Name = 'Matt' THEN 'Walker'
END)
WHERE Name IN ('John', 'Matt');
Let's say there are 3 tables: Genders, Countries and Users. Users has among others a column named Gender and also a column named Country.
I want to add a new entry to Users and select one of the columns Male/Female {M, F} and a country from the rows of Countries dynamically just for testing purposes.
insert into dbo.[Users] (Gender, UserName, Country)
select Genders.Male, 'newbie', Countries.(the one which matches column CountryId) FROM Genders, Countries
I want to achieve this: 'M', 'newbie', MyCountry
After applying the suggestion from 'zip' I get the result 2 rows affected, same number as the external tables I'm referencing. The Query added 2 rows, so I guess I am missing the WHERE conditions.
The Genders Table is meant as a Property and will have only one row that I manually added.
Table Genders; 1 row
Male : uniqueidentifier
Female : uniqueidentifier
Countries is a table with many rows, so I want to select one matching the criteria of one of it's column values, say the value of column CountryId.
You can get a random value using:
insert into dbo.[Users] (Gender, UserName)
select top (1) g.Male, 'newbie'
from Genders.Male
order by newid();
I figuored the solution out. Thank you all who responded for pointing me in the right direction.
INSERT INTO dbo.[Users] (Gender, UserName, Country)
SELECT Genders.Male, 'newbie', Countries.CountryId
FROM Genders, Countries
WHERE Countries.ISO2 = '##'
'##' = 2 letter ISO of country.
Explanation:
1. INSERT INTO dbo.[Users] = Add a new row to Table "Users"
2. (Gender, UserName, Country) = Includes the columns in table "Users". If a column is not specified and it had a property of not allowing Nulls, an exception would be thrown!
3. FROM Genders, Countries = Include the external tables associated to look for
4. WHERE Countries.ISO2 = '##' = This condition allows you to precisely select which column of which row you seek. So I searched for a certain row where a column named ISO2 had a value '##' and looked then for the CountryId value in the same row (entry). There may be cases when multiple rows have identical value so you would have to further specify the conditions by using AND or OR oeprators.
When a table does not contain more than 1 row, I should not have to apply WHERE Conditions. It will select the default one existing. But because the Countries Table had multiple items (3 Rows), leaving the WHERE clause out, caused to add 3 times the same User, with each row having a distinct CountryId!
Sorry for the bad title, I couldn't think of anything better. Feel free to edit.
I have to work with a db table that uses one column to store different types of information (last name if person, company name if company). A nightmare, I know, but it's what it is.
To distinguish the meaning, there is another column with an integer that specifies the type of what's in the name column.
The schema of this table looks as follows (simplified):
ID int
dtype int
name varchar(50)
So, a sample could look like this:
ID dtype name
---------------------------
1 0 Smith
2 0 Trump
3 1 ABC Ltd.
4 1 XYZ Ltd.
I'm trying to normalize this using the following T-SQL code:
WITH companies AS
(
SELECT ID, name AS company
FROM nametable WHERE dtype=1
),
people AS
(
SELECT ID, name AS person
FROM nametable WHERE dtype=0
),
SELECT * FROM companies UNION ALL SELECT * FROM people;
What I hoped to get is a new table with the schema:
ID
dtype
company
person
Or, in table view:
ID dtype person company
------------------------------------------
1 0 Smith
2 0 Trump
3 1 ABC Ltd.
4 1 XYZ Ltd.
Instead, the field is now just called person instead of name but it's still just one field for 2 types of information.
I understand I could just create a new table and insert each partial result into it but it seems there should be a simpler way. Any advice appreciated.
It seems you need case when which helps you
select ID, dtype,case when dtype=0 then name end AS company,
case when dtype=1 then name end AS person
FROM nametable
The CASE statement goes through conditions and return a value when condition is met, from your sample input and output its clear you want to create type wise new column ,so i used case Statement
You don't need to use UNION for this at all. A better approach would be using a bit of aggregation.
SELECT ID,
MAX(CASE WHEN dtype = 0 THEN [name] END) AS company
MAX(CASE WHEN dtype = 1 THEN [name] END) AS person
FROM nametable
GROUP BY ID;
UNION (ALL) doesn't "care" for aliases though. It combines the datasets it receives into 1. All the datasets must have the same definition and the dataset returned will have the same definition. If the datasets have different aliases for columns, the aliases supplied in the first dataset will be used. UNION doesn't detect that the datasets have different names for the columns and therefore return the different names as different columns; that's not what a UNION does.
Edit: well this will give the OP the data they want, however, there's no need for the aggregation. I was honestly expected ID's to be a shared resource; because that's normally the only time you have such horrid tables. The fact that it isn't just makes this table even more confused...
I'm having an issue copying one table's data to another. I have around 100 or so individual tables that have generally the same field names but not always. I need to be able to copy and map the fields. example: source table is BROWARD and has column names broward_ID, name, dob, address (the list goes on). The temp table I want to copy it to has ID, name, dob, address etc.
I'd like to map the fields like broward_ID = ID, name = name, etc. But many of the other tables are different in column name, so I will have to write a query for each one. Once I figure out the first on, I can do the rest. Also the column in both tables are not in order either..thanks in advance for the TSQL...
With tables:
BROWARD (broward_ID, name, dob, address) /*source*/
TEMP (ID, name, address,dob) /*target*/
If you want to copy information from BROWARD to TEMP then:
INSERT INTO TEMP SELECT broward_ID,NAME,ADDRESS,DOB FROM BROWARD --check that the order of columns in select represents the order in the target table
If you want only copy values of broward_ID and name then:
INSERT INTO TEMP(ID, name) SELECT broward_ID,NAME FROM BROWARD
Your question will resolve using update
Let's consider we have two different table
Table A
Id Name
1 abc
2 cde
Table B
Id Name
1
2
In above case want to insert Table A Name column data into Table B Name column
update B inner join on B.Id = A.Id set B.Name = A.Name where ...
I have my database structure like this ::
Database structure ::
ATT_table- ActID(PK), assignedtoID(FK), assignedbyID(FK), Env_ID(FK), Product_ID(FK), project_ID(FK), Status
Product_table - Product_ID(PK), Product_name
Project_Table- Project_ID(PK), Project_Name
Environment_Table- Env_ID(PK), Env_Name
Employee_Table- Employee_ID(PK), Name
Employee_Product_projectMapping_Table -Emp_ID(FK), Project_ID(FK), Product_ID(FK)
Product_EnvMapping_Table - Product_ID(FK), Env_ID(FK)
I want to insert values in ATT_Table. Now in that table I have some columns like assignedtoID, assignedbyID, envID, ProductID, project_ID which are FK in this table but primary key in other tables they are simply numbers).
Now when I am inputting data from the user I am taking that in form of string like a user enters Name (Employee_Table), product_Name (Product_table) and not ID directly. So I want to first let the user enter the name (of Employee or product or Project or Env) and then value of its primary key (Emp_ID, product_ID, project_ID, Env_ID) are picked up and then they are inserted into ATT_table in place of assignedtoID, assignedbyID, envID, ProductID, project_ID.
Please note that assignedtoID, assignedbyID are referenced from Emp_ID in Employee_Table.
How to do this ? I have got something like this but its not working ::
INSERT INTO ATT_TABLE(Assigned_To_ID,Assigned_By_ID,Env_ID,Product_ID,Project_ID)
VALUES (A, B, Env_Table.Env_ID, Product_Table.Product_ID, Project_Table.Project_ID)
SELECT Employee_Table.Emp_ID AS A,Employee_Table.Emp_ID AS B, Env_Table.Env_ID, Project_Table.Project_ID, Product_Table.Product_ID
FROM Employee_Table, Env_Table, Product_Table, Project_Table
WHERE Employee_Table.F_Name= "Shantanu" or Employee_Table.F_Name= "Kapil" or Env_Table.Env_Name= "SAT11A" or Product_Table.Product_Name = "ABC" or Project_Table.Project_Name = "Project1";
The way this is handled is by using drop down select lists. The list consists of (at least) two columns: one holds the Id's teh database works with, the other(s) store the strings the user sees. Like
1, "CA", "Canada"
2, "USA", 'United States"
...
The user sees
CA | Canada
USA| United States
...
The value that gets stored in the database is 1, 2, ... whatever row the user selected.
You can never rely on the exact, correct input of users. Sooner or later they will make typo's.
I extend my answer, based on your remark.
The problem with the given solution (get the Id's from the parent tables by JOINing all those parent tables together by the entered text and combining those with a number of AND's) is that as soon as one given parameter has a typo, you will get not a single record back. Imagine the consequences when the real F_name of the employee is "Shant*anu*" and the user entered "Shant*aun*".
The best way to cope with this is to get those Id's one by one from the parent tables. Suppose some FK's have a NOT NULL constraint. You can check if the F_name is filled in and inform the user when he didn't fill that field. Suppose the user eneterd "Shant*aun*" as name, the program will not warn the user, as something is filled in. But that is not the check the database will do, because the NOT NULL constraints are defined on the Id's (FK). When you get the Id's one by one from the parent tables. You can verify if they are NOT NULL or not. When the text is filled in, like "Shant*aun*", but the returned Id is NULL, you can inform the user of a problem and let him correct his input: "No employee by the name 'Shantaun' could be found."
SELECT $Emp_ID_A = Emp_ID
FROM Employee_Table
WHERE F_Name= "Shantanu"
SELECT $Emp_ID_B = Emp_ID
FROM Employee_Table
WHERE B.F_Name= "Kapil"
SELECT $Env_ID = Env_ID
FROM Env_Table
WHERE Env_Table.Env_Name= "SAT11A"
SELECT $Product_ID = Product_ID
FROM Product_Table
WHERE Product_Table.Product_Name = "ABC"
SELECT $Project_ID = Project_ID
FROM Project_Table
WHERE Project_Name = "Project1"
Please use AND instead of OR.
INSERT INTO ATT_TABLE(Assigned_To_ID,Assigned_By_ID,Env_ID,Product_ID,Project_ID)
SELECT A.Emp_ID, B.Emp_ID, Env_Table.Env_ID, Project_Table.Project_ID, Product_Table.Product_ID
FROM Employee_Table A, Employee_Table B, Env_Table, Product_Table, Project_Table
WHERE A.F_Name= "Shantanu"
AND B.F_Name= "Kapil"
AND Env_Table.Env_Name= "SAT11A"
AND Product_Table.Product_Name = "ABC"
AND Project_Table.Project_Name = "Project1";
But it is best practice to use drop down list in your scenario, i guess.