Inserting data into table variable - sql

I want to know if it's possible to insert data into a table variable from a select query. When using a variable table before I have inserted the values and typed them myself.
I have come up with the following select query that displays the latest comment for a repair order. It returns 37 records and I wanted to know if it's possible to insert those into a variable table.
SELECT
a.CH_REPREF, a.CH_DATE, a.CH_CRTIME,
b.[Latest Customer Comment], a.CH_CRUSER, a.CH_CCOMMNT
FROM
(SELECT
CH_REPREF,
MAX(CH_REPREF1) As [Latest Customer Comment]
FROM
dbo.V_CSRPCH
WHERE
CH_CCOMMNT IS NOT NULL
AND CH_CCOMMNT NOT LIKE 'X'
GROUP BY
CH_REPREF) b,
(SELECT
CH_REPREF, CH_DATE, CH_CRTIME, CH_REPREF1,
CH_CRUSER, CH_CCOMMNT, CH_ACCOUNT
FROM
dbo.V_CSRPCH) a
WHERE
CH_REPREF1 = [Latest Customer Comment]
AND CH_ACCOUNT = 'DDCHC'
I have started the table variable with the following, but am stuck whether it's possible to fill it with the data returned by the select query:
Declare #tbl_last_customer_comment TABLE
(CH_REPREF nvarchar(10),
CH_DATE smalldatetime,
CH_CRTIME nvarchar(8),
Latest int,
CH_CRUSER nvarchar(8),
CH_CCOMMNT text)

just do it as 'constant' table-
INSERT INTO #tbl_last_customer_comment
SELECT a.CH_REPREF, a.CH_DATE, a.CH_CRTIME,b.[Latest Customer Comment],a.CH_CRUSER,a.CH_CCOMMNT
FROM (SELECT CH_REPREF, MAX(CH_REPREF1) As [Latest Customer Comment]
FROM dbo.V_CSRPCH
WHERE CH_CCOMMNT IS Not Null AND CH_CCOMMNT Not Like 'X'
GROUP BY CH_REPREF) b,
(SELECT CH_REPREF, CH_DATE, CH_CRTIME,CH_REPREF1, CH_CRUSER, CH_CCOMMNT, CH_ACCOUNT
FROM dbo.V_CSRPCH) a
WHERE CH_REPREF1 = [Latest Customer Comment] AND CH_ACCOUNT = 'DDCHC'

Related

Invalid Object Name when i execute a procedure that update a table

I have the following
use salesdb
go
create procedure monthlysales as
begin
create table MyTable( SalesFactID integer identity(1,1),
ReportingMth date,
customer_id varchar(50),
ReferenceID navarchar(50),
LstOrderDte date);
Insert into MyTable
select
businessMth,
saleid as referenceid,
null as lastorderte
from sourcetble;
update MyTable
set lastorderte = sls.max_orderdte
from ( select
st.customer_id,
ftmytbl.ReportingMth,
max(salesdate) as max_orderdte
from sales_table st
left outer join mytable ftmytbl
on ftmytbl.customerid=st.customerRef
where saleste<=ftmytbl.ReportingMth
group by customer_id
)up
where mytable.customer_id=up.customer_id
and mytable.reportingmth=up.ReportingMth;
end;
execute monthlysales
error invalid object name mytable.reportingmth
How can i fix this? Please assist.
Search for that text. Where is it? It is in the where clause of the outermost select statement. You used a derived table named up (which is a crap name, btw - as are many of your names) in the join. The outer query knows only 2 tables - up and MyTable (or is it mytable? BE CONSISTENT!) and can only refer to columns in those tables.
To correct this particular problem, change this:
and mytable.reportingmth=up.ReportingMth;
to
and MyTable.ReportingMth = up.ReportingMth;
But that will only fix one problem. There seem to be others yet to be found.

How to copy the column id from another table?

I'm stuck with this since last week. I have two tables, where the id column of CustomerTbl correlates with CustomerID column of PurchaseTbl:
What I'm trying to achieve is I want to duplicate the data of the table from itself, but copy the newly generated id of CustomerTbl to PurchaseTbl's CustomerID
Just like from the screenshots above. Glad for any help :)
You may use OUTPUT clause to access to the new ID. But to access to both OLD ID and NEW ID, you will need to use MERGE statement. INSERT statement does not allow you to access to the source old id.
first you need somewhere to store the old and new id, a mapping table. You may use table variable or temp table
declare #out table
(
old_id int,
new_id int
)
then the merge statement with output clause
merge
#CustomerTbl as t
using
(
select id, name
from CustomerTbl
) as s
on 1 = 2 -- force it to `false`, not matched
when not matched then
insert (name)
values (name)
output -- the output clause
s.id, -- old_id
inserted.id -- new_id
into #out (old_id, new_id);
after that you just use the #out to join back using old_id to obtain the new_id for the PurchaseTbl
insert into PurchaseTbl (CustomerID, Item, Price)
select o.new_id, p.Item, p.Price
from #out o
inner join PurchaseTbl p on o.old_id = p.CustomerID
Not sure what your end game is, but one way you could solve this is this:
INSERT INTO purchaseTbl ( customerid ,
item ,
price )
SELECT customerid + 3 ,
item ,
price
FROM purchaseTbl;

How to insert using different table based on condition in same query

I am merging data in one table from tables of 2 database. Structure is as per below:
Table in new Database :
User Table : {UserName,Email}
Table in Database1 :
User Table : {UserName,Email,LastLogin}
Table in Database2 :
User Table : {UserName,Email,LastLogin}
Now i need to write query that if Email address are same in 2 tables from database 1 and database2 then we need to insert record where LastLogin is latest.
Can someone suggest over this.
I think you are in need of this.. :)
Try modifying it accordingly..
declare #Email_1 nvarchar(100),#Email_2 nvarchar(100),#UserName nvarchar(100),#Lastlogin_1 datetime,#Lastlogin_2 datetime,#loop int=0
use [Database1]
while #loop != (select count(Distinct Email) from [User Table])
BEGIN
use [Database1]
set #Email_1 = (select Distinct Email from [User Table] order by email asc offset #loop rows fetch next 1 rows only)
set #LastLogin_1 = (select top 1 max(LastLogin) from [User Table] where email=#Email_1)
use [Database2]
set #Email_2 = (select top 1 Email from [User Table] where Email like '%#Email_1%')
set #LastLogin_2 = (select top 1 max(LastLogin) from [User Table] where email=#Email_2)
if #email_1=#email_2
BEGIN
if #LastLogin_1>#LastLogin_2
BEGIN
use [Database_1]
set #username = (select top 1 Username from [user table] where email=#email_1 and lastlogin=#Lastlogin_1)
use [New Database]
insert into [User Table]
select #username,#email_1
END
else if #LastLogin_1<#LastLogin_2
BEGIN
use [Database_2]
set #username = (select top 1 Username from [user table] where email=#email_2 and lastlogin=#Lastlogin_2)
use [New Database]
insert into [User Table]
select #username,#email_1
use [Database1]
END
END
set #loop=#loop+1
END
My following code are assuming all tables are in one database, this is more for demo convenience purpose. In real world, when you have tables in different databases, then you need to use 3-part naming convention, i.e.
[DB].[Schema].[Table]
Also I am testing in sql server environment.
use tempdb
drop table dbo.merge_tbl, dbo.t1, dbo.t2;
create table dbo.merge_tbl (username varchar(30), email varchar(30));
create table dbo.t1 (username varchar(30), email varchar(30), lastlogin datetime)
create table dbo.t2 (username varchar(30), email varchar(30), lastlogin datetime)
go
-- insert a few records to tables
insert into dbo.t1 (username, email, lastlogin)
values ('james1', 'j#a.com', '20161001'), ('jenny1', 'j2#b.com', '20161002'), ('jeffrey1', 'j3#c.com', '20150101')
insert into dbo.t2(username, email, lastlogin)
values ('james2', 'j#a.com', '20161006'), ('jenny2', 'j2#b.com', '20151002'), ('jeffrey2', 'j4#c.com', '20170101')
go
-- this is the insert statement
insert into dbo.merge_tbl (username, email)
select case when t1.lastlogin >= t2.lastlogin then t1.username else t2.username end
, case when t1.lastlogin >= t2.lastlogin then t1.email else t2.email end
from dbo.t1
inner join dbo.t2
on t1.email = t2.email;
go
-- check result
select * from dbo.merge_tbl
Here is the result
follow 3 part naming convention([Database Name].[Schema].[Table name]) while accessing your table in different database. Also there may be multiple log in entries for a single user in the table [User Table] ,so use grouping function in such scenario.
If you are using SQL Server,use the below script for achieving the result.
INSERT INTO [New Database].dbo.[User Table] (UserName,Email)
SELECT CASE WHEN MAX(a.LastLogin)>=MAX(b.LastLogin) THEN a.[UserName] ELSE b.[UserName] END [UserName],a.Email
FROM Database1.dbo.[User Table] a
JOIN Database2.dbo.[User Table] b
ON a.Email=b.Email
GROUP BY a.[UserName],b.[UserName],a.Email
Assuming the three database db0, db1 and db2. For merging data in database db0 run the following query:
insert into db0.user('name','email')
select name, email from (
select db1.name,db1.email,
case
when db1.user.lastlogin >= db2.user.lastlogin
then db1.user.lastlogin
else db2.user.lastlogin
end as lastlogin
from db1.user,db2.user
where db1.user.email = db2.user.email ) as a
UPDATE
insert into db0.user(all columns)
select * from (
select "apply case for some columns" from db1.user,db2.user
where "apply your condition" ) as a
consider the following facts:
1. In this above query we are doing cross multiplication between db1.user and db2.user by which we get all possible values from these 2 tables
If you want to apply condition in "where" clause for email(for example db1.user.email = db2.user.email) then you can write db1.user.email or db2.user.email after "select", because both values are same.
If you want to apply >= or <= condition you have to apply "case" after "select".Because you have to fetch any one value from 2 tables
For example you want to fetch lastlogin data, for this condition I have applied case in lastlogin column. By this condition you will get column value from either db1.user or db2.user.
conditions in where clause can be written in case form after "select" also.
Please have a look on the UPDATE portion.
And I went for prayer, that is why this late reply.
If it helps mark as right answer.
Thank you

I am looking for a way for a trigger to insert into a second table only where the value in table 1 changes

I am looking for a way for a trigger to insert into a second table only where the value in table 1 changes. It is essentially an audit tool to trap any changes made. The field in table 1 is price and we want to write additional fields.
This is what I have so far.
CREATE TRIGGER zmerps_Item_costprice__update_history_tr ON [ITEM]
FOR UPDATE
AS
insert into zmerps_Item_costprice_history
select NEWID(), -- unique id
GETDATE(), -- CURRENT_date
'PRICE_CHANGE', -- reason code
a.ima_itemid, -- item id
a.ima_price-- item price
FROM Inserted b inner join item a
on b.ima_recordid = a.IMA_RecordID
The table only contains a unique identifier, date, reference(item) and the field changed (price). It writes any change not just a price change
Is it as simple as this? I moved some of the code around because comments after the comma between columns is just painful to maintain. You also should ALWAYS specify the columns in an insert statement. If your table changes this code will still work.
CREATE TRIGGER zmerps_Item_costprice__update_history_tr ON [ITEM]
FOR UPDATE
AS
insert into zmerps_Item_costprice_history
(
UniqueID
, CURRENT_date
, ReasonCode
, ItemID
, ItemPrice
)
select NEWID()
, GETDATE()
, 'PRICE_CHANGE'
, d.ima_itemid
, d.ima_price
FROM Inserted i
inner join deleted d on d.ima_recordid = i.IMA_RecordID
AND d.ima_price <> i.ima_price
Since you haven't provided any other column names I Have used Column2 and Column3 and the "Other" column names in the below example.
You can expand adding more columns in the below code.
overview about the query below:
Joined the deleted and inserted table (only targeting the rows that has changed) joining with the table itself will result in unnessacary processing of the rows which hasnt changed at all.
I have used NULLIF function to yeild a null value if the value of the column hasnt changed.
converted all the columns to same data type (required for unpivot) .
used unpivot to eliminate all the nulls from the result set.
unpivot will also give you the column name its has unpivoted it.
CREATE TRIGGER zmerps_Item_costprice__update_history_tr
ON [ITEM]
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON ;
WITH CTE AS (
SELECT CAST(NULLIF(i.Price , d.Price) AS NVARCHAR(100)) AS Price
,CAST(NULLIF(i.Column2 , d.Column2) AS NVARCHAR(100)) AS Column2
,CAST(NULLIF(i.Column3 , d.Column3) AS NVARCHAR(100)) AS Column3
FROM dbo.inserted i
INNER JOIN dbo.deleted d ON i.IMA_RecordID = d.IMA_RecordID
WHERE i.Price <> d.Price
OR i.Column2 <> d.Column2
OR i.Column3 <> d.Column3
)
INSERT INTO zmerps_Item_costprice_history
(unique_id, [CURRENT_date], [reason code], Item_Value)
SELECT NEWID()
,GETDATE()
,Value
,ColumnName + '_Change'
FROM CTE UNPIVOT (Value FOR ColumnName IN (Price , Column2, Column3) )up
END
As I understand your question correctly, You want to record change If and only if The column Price value is changes, you dont need any other column changes to be recorded
here is your code
CREATE TRIGGER zmerps_Item_costprice__update_history_tr ON [ITEM]
FOR UPDATE
AS
if update(ima_price)
insert into zmerps_Item_costprice_history
select NEWID(), -- unique id
GETDATE(), -- CURRENT_date
'PRICE_CHANGE', -- reason code
a.ima_itemid, -- item id
a.ima_price-- item price
FROM Inserted b inner join item a
on b.ima_recordid = a.IMA_RecordID

T-SQL - Pivot by week

I'm currently trying to create a T-SQL, which runs through a list of deliveries in a table, and groups them by the Customer and the Depot - so each row will be
Customer, Depot, Total Value (sum of a column called Rate)
However, the customer would like the 'total value' split into the last 9 weeks - so rather than total value, we'll have columns like this:
22/01/2012 29/01/2012 05/02/2012 12/02/2012 19/02/2012 26/02/2012 04/03/2012 11/03/2012 18/03/2012
The dates would of course change for when they run the query - it'll just be the last 9 weeks. They also want a column for the Average of all these.
I understand pivot may help me but I'm a bit stumped on how to do this. Here's my current query:
SELECT d.Name AS 'Depot, s.Name AS 'Customer', SUM(c.Rates) AS 'Total Value'
FROM Deliveries AS c INNER JOIN Account AS s ON c.Customer = s.ID
INNER JOIN Depots AS d ON c.CollectionDepot = d.Letter
GROUP BY d.Name, s.Name
Many thanks!
EDIT: Here's a screenshot of the data currently - we won't need the 'total' column on the end, just there to show you. The 'Date' column is present in the Deliveries table and is called TripDate
Without knowing your exact data. It hard to predict what you are getting. But I can give you a suggestion of a solution.
Table structure
CREATE TABLE Deliveries
(
Customer INT,
CollectionDepot INT,
Rates FLOAT,
TripDate DATETIME
)
CREATE TABLE Account
(
Name VARCHAR(100),
ID INT
)
CREATE TABLE Depots
(
Name VARCHAR(100),
Letter INT
)
Test data
INSERT INTO Deliveries
VALUES
(1,1,452,GETDATE()-10),
(1,1,800,GETDATE()-30),
(1,1,7895,GETDATE()-2),
(1,1,451,GETDATE()-2),
(1,1,478,GETDATE()-89),
(1,1,4512,GETDATE()-31),
(1,1,782,GETDATE()-20),
(1,1,652,GETDATE()-5),
(1,1,752,GETDATE()-452)
INSERT INTO Account
VALUES
('Customer 1',1)
INSERT INTO Depots
VALUES
('Depot 1',1)
Table that contains the ranges and the formated date
CREATE TABLE #tmp
(
StartDate DATETIME,
EndDate DATETIME,
FomatedDate VARCHAR(20)
)
Calculate the date ranges
;WITH Nbrs ( n ) AS (
SELECT 0 UNION ALL
SELECT 1+n FROM Nbrs WHERE n < 8 )
INSERT INTO #tmp
SELECT
DATEADD(WEEK,-n-1,GETDATE()),
DATEADD(WEEK,-n,GETDATE()),
convert(varchar, DATEADD(WEEK,-n,GETDATE()), 112)
FROM
Nbrs
ORDER BY
-n
The date columns for the pivot
DECLARE #cols VARCHAR(MAX)
SELECT #cols = COALESCE(#cols + ','+QUOTENAME(FomatedDate),
QUOTENAME(FomatedDate))
FROM
#tmp
Declaring some dynamic sql and executing it
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
Depots.Name AS Depot,
Account.Name AS Customer,
Deliveries.Rates,
tmp.FomatedDate,
AVG(Deliveries.Rates) OVER(PARTITION BY 1) AS Average,
SUM(Deliveries.Rates) OVER(PARTITION BY 1) AS Total
FROM
Deliveries
JOIN Account
ON Deliveries.Customer = Account.ID
JOIN Depots
ON Deliveries.CollectionDepot = Depots.Letter
JOIN #tmp AS tmp
ON Deliveries.TripDate BETWEEN tmp.StartDate AND tmp.EndDate
) AS p
PIVOT
(
AVG(rates)
FOR FomatedDate IN ('+#cols+')
) AS pvt'
EXECUTE(#query)
And then cleaning up after myself.
DROP TABLE Deliveries
DROP TABLE Account
DROP TABLE Depots
DROP TABLE #tmp
You would have to make use of the PIVOT Keyword which is available in your version of SQL Server. I have outlined how your query should look, of course some tweaking will be required since it is difficult to test without having a copy of your data.
SELECT Depots.Name AS 'Depot', Account.Name, '22/01/2012', '29/01/2012', '05/02/2012', '12/02/2012',
FROM
(SELECT Name,
FROM Deliveries
INNER JOIN Account ON Deliveries.Customer = Account.ID
INNER JOIN Depots ON Account.CollectionDepot) AS Source
PIVOT
(
SUM(Deliveries.Rates)
FOR Date IN ('22/01/2012', '29/01/2012', '05/02/2012', '12/02/2012')
) AS 'Pivot Table'
For reference you could use this as a guide:
http://msdn.microsoft.com/en-us/library/ms177410.aspx