INSERT into table including foreign keys to related tables - database

Please if someone could help,
I have three tables: 1. Clients; 2 Accounts; 3. Transactions ...
I want to get ClientID by ClientName and also AccountID by AccountName and then insert those ID`s to Transactions and some other values for some other fields that are known ...
Clients
ClientID | ClientName | ...
Accounts
AccountID | AccountName | ...
Transactions
TransID | Account ID | ClientID | Value | Tax | Total
how can i do it ... i tried many many forms of the insert statement but it didnt work
I tried this:
INSERT INTO Transactions (AccountID, ClientID, Value) Values
(SELECT AccountID WHERE AccountName = 'Some Name'
FROM Accounts, SELECT ClientID WHERE ClientName = 'Some Name' FROM Clients, 30.00 )

Value is a reserved word in MS Access.
I think you want something like this:
INSERT INTO Transactions ( AccountID, ClientID, [Value] )
SELECT Accounts.AccountID, Clients.ClientID, 30.00 AS Expr1
FROM Accounts, Clients
WHERE (((Clients.ClientName)='Jimmy') AND ((Accounts.AccountName)='Mark'));
You'll need to rewrite the SQL to properly fit your tables/table names possibly but this worked for me.
You should also make sure Value is a Double data type, not a long integer. (which is the default for a Number field)

Related

SQL - aggregate related accounts - maually set up ID

I have two tables:
Account & Amount column
list of related accounts
Data samples:
Account | Amount
--------+---------
001 | $100
002 | $150
003 | $200
004 | $300
Account | Related Account
--------+------------------
001 | 002
002 | 003
003 | 002
My goal is to be able to aggregate all related accounts. From table two - 001,002 & 003 are actually all related to each other. What I would like to be able to do is to get a sum of all related accounts. Possibly ID 001 to 003 as Account #1, so I can aggregate them.
Result below
ID | Account | Amount
-----+-----------+--------
#1 | 001 | $100
#1 | 002 | $150
#1 | 003 | $200
#2 | 004 | $300
I can then manipulate the above table as below (final result)
ID | Amount
-----+--------
#1 | $450
#2 | $300
I tried doing a join, but it doesn't quite achieve what I want. I still have a problem relating account 001 with 003 (they are indirectly related because 002 is related with both 001 and 003.
If anyone can point me to the right direction, will be much appreciated.
Well, you really made this harder then it should be.
If you could change the data in the second table, so it will not contain reversed duplicates (in your sample data - 2,3 and 3,2) it would simplify the solution.
If you could refactor both tables into a single table, where the related column is a self referencing nullable foreign key, it would simplify the solution even more.
Let's assume for a minute you can't do either, and you have to work with the data as provided. So the first thing you want to do is to ignore the reversed duplicates in the second table. This can be done using a common table expression and a couple of case expressions.
First, create and populate sample tables (Please save us this step in your future questions):
DECLARE #TAccount AS TABLE
(
Account int,
Amount int
)
INSERT INTO #TAccount (Account, Amount) VALUES
(1, 100),
(2, 150),
(3, 200),
(4, 300)
DECLARE #TRelatedAccounts AS TABLE
(
Account int,
Related int
)
INSERT INTO #TRelatedAccounts (Account, Related) VALUES
(1,2),
(2,3),
(3,2)
You want to get only the first two records from the #TRelatedAccounts table.
This is the AccountAndRelated CTE.
Now, you want to left join the #TAccount table with the results of this query, so for each Account we will have the Account, the Amount, and the Related Account or NULL, if the account is not related to any other account or it's the first on the relationship chain.
This is the CTERecursiveBase CTE.
Then, based on that you can create a recursive CTE (called CTERecursive), and finally select the sum of amount from the recursive CTE based on the root of the recursion.
Here is the entire script:
;WITH AccountAndRelated AS
(
SELECT DISTINCT CASE WHEN Account > Related THEN Account Else Related END As Account,
CASE WHEN Account > Related THEN Related Else Account END As Related
FROM #TRelatedAccounts
)
, CTERecursiveBase AS
(
SELECT A.Account, Related, Amount
FROM #TAccount As A
LEFT JOIN AccountAndRelated As R ON A.Account = R.Account
)
, CTERecursive AS
(
SELECT Account As Id, Account, Related, Amount
FROM CTERecursiveBase
WHERE Related IS NULL
UNION ALL
SELECT Id, B.Account, B.Related, B.Amount
FROM CTERecursiveBase AS B
JOIN CTERecursive AS R ON B.Related = R.Account
)
SELECT Id, SUM(Amount) As TotalAmount
FROM CTERecursive
GROUP BY Id
Results:
Id TotalAmount
1 450
4 300
You can see a live demo on rextester.
Now, Let's assume you can modify the data of the second table. You can use the AccountAndRelated cte to get only the records you need to keep in the #TRelatedAccounts table - This means you can skip the AccountAndRelated cte and use the #TRelatedAccounts directly in the CTERecursiveBase cte.
You can see a live demo of that as well.
Finally, let's assume you can refactor your database. In that case, I would recommend joining the two tables together - so your #TAccount table would look like this:
Account Amount Related
1 100 NULL
2 150 1
3 200 2
4 300 NULL
Then you only need the recursive cte.
Here is a live demo of that option as well.

T-SQL Select, manipulate, and re-insert via stored procedure

The short version is I'm trying to map from a flat table to a new set of tables with a stored procedure.
The long version: I want to SELECT records from an existing table, and then for each record INSERT into a new set of tables (most columns will go into one table, but some will go to others and be related back to this new table).
I'm a little new to stored procedures and T-SQL. I haven't been able to find anything particularly clear on this subject.
It would appear I want to something along the lines of
INSERT INTO [dbo].[MyNewTable] (col1, col2, col3)
SELECT
OldCol1, OldCol2, OldCol3
FROM
[dbo].[MyOldTable]
But I'm uncertain how to get that to save related records since I'm splitting it into multiple tables. I'll also need to manipulate some of the data from the old columns before it will fit into the new columns.
Thanks
Example data
MyOldTable
Id | Year | Make | Model | Customer Name
572 | 2001 | Ford | Focus | Bobby Smith
782 | 2015 | Ford | Mustang | Bobby Smith
Into (with no worries about duplicate customers or retaining old Ids):
MyNewCarTable
Id | Year | Make | Model
1 | 2001 | Ford | Focus
2 | 2015 | Ford | Mustang
MyNewCustomerTable
Id | FirstName | LastName | CarId
1 | Bobby | Smith | 1
2 | Bobby | Smith | 2
I would say you have your OldTable Id to preserve in new table till you process data.
I assume you create an Identity column Id on your MyNewCarTable
INSERT INTO MyNewCarTable (OldId, Year, Make, Model)
SELECT Id, Year, Make, Model FROM MyOldTable
Then, join the new table and above table to insert into your second table. I assume your MyNewCustomerTable also has Id column with Identity enabled.
INSERT INTO MyNewCustomerTable (CustomerName, CarId)
SELECT CustomerName, new.Id
FROM MyOldTable old
JOIN MyNewCarTable new ON old.Id = new.OldId
Note: I have not applied Split of Customer Name to First Name and
Last Name as I was unsure about existing data.
If you don't want your OldId in MyNewCarTable, you can DELETE it
ALTER TABLE MyNewCarTable DROP COLUMN OldId
You are missing a step in your normalization. You do not need to duplicate your customer information per vehicle. You need three tables for 4th Normal form. This will reduce storage size and more importantly allow an update to the customer data to take place in one location.
Customer
CustomerID
FirstName
LastName
Car
CarID
Make
Model
Year
CustomerCar
CustomerCarID
CarID
CustomerID
DatePurchaed
This way you can have multiple owners per car, multiple cars per owner and only one record needs to be updated per car and or customer...4th Normal Form.
If I am reading this correctly, you want to take each row from table 1, and create a new record into table A using some of that row data, and then data from the same original row into Table B, Table C but referencing back to Table A again?
If that's the case, you will create TableA with an Identity and make thats the PK.
Insert the required column data into that table and use the #IDENTITY to retrieve the last identity value, then you will insert the remaining data from the original table into the other tables, TableB, TableC, etc. and use the identity you retrieved from TableA as the FK in the other tables.
By Example:
Table 1 has columns col1, col2, col3, col4, col5
Table A has TabAID, col1, col2
Table B has TabBID, TabAID, col3
TableC has TabCID, TabAID, col4
When the first row is read, the values for col1 & col2 are inserted into TableA.
The Identity is captured from that row inserted, and then value for col3 AND the identity are entered into TableB, and then value for col4 AND the identity are entered into TableC.
This is a standard data migration technique for normalizing data.
Hope this assists,

Stored procedure using table with recipients

I have a table I would like split and emailed to the corresponding staff member of that department, I have two tables, Table 1 contains all the transaction data against the department and is live, Table 2 is static which essentially lists the staff member who is responsible for the each department.
I need to split up table 1 by Department then lookup the email for the corresponding staff member from table2 and send the split table.
Table 1:
| Customer | ? | Department
| Customer | ? | Department1
| Customer | ? | Department2
Table2:
| Department | Staff | Email
| Department1 | Staff1 | Email
| Department2 | Staff2 | Email
I was wondering, would it be possible to create a stored procedure to do this or would I have to create a subscription in SSRS for each individual staff member?
Thanks,
Neil
I would thoroughly recommend making a simple SSRS report and distributing it via a Data Driven Subscription. The queries below will get you started on your data extracts and you can follow a guide here on how to set up an SSRS Data Driven Subscription.
They are very simple to create, you only need the one subscription to send an email to every Department and they are very easy to maintain, even by someone else with no idea what it does.
declare #t1 table(Cust nvarchar(100)
,Cols nvarchar(100)
,Dept nvarchar(100)
)
declare #t2 table(Dept nvarchar(100)
,Staff nvarchar(100)
,Email nvarchar(100)
)
insert into #t1 Values
('Customer','?','Department1')
,('Customer','?','Department2')
,('Customer','?','Department3')
insert into #t2 Values
('Department1','Staff1','Email1')
,('Department2','Staff2','Email2')
,('Department3','Staff3','Email3')
-- Use this query in your Data Driven Subscription to generate the list of Departments and their respective Emails:
select distinct t1.Dept
,t2.Email
from #t1 t1
left join #t2 t2
on(t1.Dept = t2.Dept)
-- Then use this query in your report to list out the contents of Table 1, matching the #SSRSDeptParameter value in the Data Driven Subscription options.
select t1.Cust
,t1.Cols
,t1.Dept
,t2.Email
from #t1 t1
left join #t2 t2
on(t1.Dept = t2.Dept)
where #t1.Dept = #SSRSDeptParameter

SQL Server aggregate function with sum

I want to use an aggregate function in SQL Server to sum the number of seats:
The table is like that (it's all the same software just version changes)
OrderID | CustomerID | ProductID | Product Name | No of Seats
1 | 11 | 351-0212-4 | soft v601,Download | 3
2 | 11 | 361-0313-5 | soft v701,Upgrade | 2
3 | 12 | 341-1210-4 | soft v501,Download | 5
4 | 12 | 351-0212-5 | soft v601,Upgrade | 2
...
And I want a result like
Sum(no of seats)
8
So If a customer already bought the software but have upgraded keep number of seats for the customer.
e.g.:
Customer 11 bought 3 licences of our soft and then he bought two upgrades of a newer vesion so the sum for him should be 3 instead of 5.
Is that something possible to do in SQL ?
I hope I've been clear if not let me know.
Thanks in advance.
something like
select CustomerID, sum([No of Seats])
from <your table>
where [Product Name] not like '%upgrade%'
group by CustomerID
But in general - filter out those you don't want to see in the results and then sum. And if you want total number (not per customer):
select sum([No of Seats])
from <your table>
where [Product Name] not like '%upgrade%'
you should add boolean column, like 'isActive', then your select can be like this
select customerid, sum(numberOfSeats) from table
where isActive = 1
group by customerid
You have some normalization problems. The Product Name column is (presumably) redundant with the ProductID column, plus Product Name
apparently carries two logically distinct pieces of information: the name itself, and whether that product is an upgrade.
It would be better to split this into two tables, say Products and Orders. The Products table would have columns ProductID (primary key), Product_Name, and Is_Upgrade, and the Orders table would have columns OrderID (primary key), CustomerID (foreign key), ProductID (foreign key), and NumberOfSeats.
Given what you now have, however, and assuming that you want to avoid counting seats where the product name ends in 'Upgrade', you seem to want a query along these lines:
SELECT SUM("No of seats")
FROM Orders
WHERE CustomerID = 11 AND "Product Name" NOT LIKE '%Upgrade'

SQL Script: Updating a column with another table pivoting on an ID

I have two SQL Server tables: ORDERS and DELIVERIES.
I would like to update the ORDERS table with a value from DELIVERIES. The ORDERS PK (OrderID) is common to both tables. Also, I would like to restrict the action to a specific CustomerID (within ORDERS).
ORDERS table:
OrderID | AccountID | AnalysisField1
DELIVERIES table:
DeliveryID | OrderID | AddressName
I want to update ORDERS.AnalysisField1 with the value from DELIVERIES.AddressName (linked by OrderID) but only where ORDERS.AccountID = '12345'
Please help. JM
Then try to use something like this:
UPDATE dbo.Orders
SET AnalysisField1 = d.Addressname
FROM dbo.Deliveries d
WHERE
d.OrderID = dbo.Orders.OrderID
AND dbo.Orders.AccountID = '12345'
If your AccountID column is of a numerical type (which the ID suffix would suggest), then you should not put unnecessary single quotes around the value in the WHERE clause:
AND dbo.Orders.AccountID = 12345

Resources