I have a status table, and another table containing additional data. My object IDs are the PK in the status table, so I need to insert those into the additional data table for each new row.
I need to insert a new row into my statusTable for each new listing, containing just constants.
declare #temp TABLE(listingID int)
insert into statusTable(status, date)
output Inserted.listingID into #temp
select 1, getdate()
from anotherImportedTable
This gets me enough new listing IDs to use.
I now need to insert the actual listing data into another table, and map each row to one of those listingIDs -
insert into listingExtraData(listingID, data)
select t.listingID, a.data
from #temp t, anotherImportedTable a
Now this obviously doesn't work, because otherDataTable and the IDs in #temp are unrelated... so I get far too many rows inserted.
How can I insert each row from anotherImportedTable into listingExtraData along with a unique newly created listingID? could I possibly trigger some more sql at the point I do the output in the first block of sql?
edit: thanks for the input so far, here's what the tables look like:
anotherImportedTable:
data
statusTable:
listingID (pk), status, date
listingExtraData:
data, listingID
You see that I only want to create one entry into statusTable per row in anotherImportedTable, then put one listingID with a row from anotherImportedTable into listingExtraData... I'm thinking that I might have to resort to a cursor perhaps?
Ok, here's how you can do it (if I'm right about what you actually want to do):
insert into listingExtraData(listingID, data)
select q1.listingID, q2.data
from
(select ListingID, ROW_NUMBER() OVER (order by ListingID) as rn from #temp t) as q1
inner join (select data, ROW_NUMBER() over (order by data) as rn from anotherImportedTable) q2 on q1.rn = q2.rn
In case you matching logic differs you will need to change sorting of anotherImportedTable. In case your match order can not be achieved by ordering anotherImportTable [in one way or another] then you're out of luck.
Related
I have a table like this
CREATE TABLE userinteractions
(
userid bigint,
dobyr int,
-- lots more fields that are not relevant to the question
);
My problem is that some of the data is polluted with multiple dobyr values for the same user.
The table is used as the basis for further processing by creating a new table. These cases need to be removed from the pipeline.
I want to be able to create a clean table that contains unique userid and dobyr limited to the cases where there is only one value of dobyr for the userid in userinteractions.
For example I start with data like this:
userid,dobyr
1,1995
1,1995
2,1999
3,1990 # dobyr values not equal
3,1999 # dobyr values not equal
4,1989
4,1989
And I want to select from this to get a table like this:
userid,dobyr
1,1995
2,1999
4,1989
Is there an elegant, efficient way to get this in a single sql query?
I am using postgres.
EDIT: I do not have permissions to modify the userinteractions table, so I need a SELECT solution, not a DELETE solution.
Clarified requirements: your aim is to generate a new, cleaned-up version of an existing table, and the clean-up means:
If there are many rows with the same userid value but also the same dobyr value, one of them is kept (doesn't matter which one), rest gets discarded.
All rows for a given userid are discarded if it occurs with different dobyr values.
create table userinteractions_clean as
select distinct on (userid,dobyr) *
from userinteractions
where userid in (
select userid
from userinteractions
group by userid
having count(distinct dobyr)=1 )
order by userid,dobyr;
This could also be done with an not in, not exists or exists conditions. Also, select which combination to keep by adding columns at the end of order by.
Updated demo with tests and more rows.
If you don't need the other columns in the table, only something you'll later use as a filter/whitelist, plain userid's from records with (userid,dobyr) pairs matching your criteria are enough, as they already uniquely identify those records:
create table userinteractions_whitelist as
select userid
from userinteractions
group by userid
having count(distinct dobyr)=1
Just use a HAVING clause to assert that all rows in a group must have the same dobyr.
SELECT
userid,
MAX(dobyr) AS dobyr
FROM
userinteractions
GROUP BY
userid
HAVING
COUNT(DISTINCT dobyr) = 1
I have to read a txt data that contains a first load that someone do, and insert data into 2 tables. this means:
At the begining tab_data and tab_list is empty.
with the first txt record, i have to validate first if "C43R" exist on "tab_list" table, if not, i have to insert and get the new ID, and after that insert that new ID created on "tab_data" table with the rest of information.
With the second record, first i have to validate if "C43R" exist on "tab_list" table, if exist i have to get the ID, and after that insert that new ID created on "tab_data" table with the rest of information.
with the fourth txt record, i have to validate first if "M23K" exist on "tab_list" table, if not, i have to insert and get the new ID, and after that insert that new ID created on "tab_data" table with the rest of information.
And the same with all the rows from the txt file.
So how can i start with this?
Does any body have a suggestion or a solution?
Really thanks, regards
You could do this with two queries. The logic would be to first feed tab_list, then tab_data. Note that you need an ordering column in txt_data for this to make sense - I assumed id.
This inserts into tab_list, while manually generating a sequence that starts at 10.
insert into tab_list(id, tab)
select tab_id, 9 + row_number() over(order by min(id))
from txt_data
group by tab_id
With this set-up at hand, you can then insert in tab_data:
insert into tab_data (id, tab_id, data)
select
99 + row_number() over(order by d.id),
l.id,
d.data
from txt_data d
inner join tab_list l on l.tab_id = d.tab_id
I have a problem I have been working on the past several hours. It is complex (for me) and I don't expect someone to do it for me. I just need the right direction.
Problem: We had the tables (below) added to our database and I need to update them based off of data already in our DailyCosts table. The tricky part is that I need to take DailyCosts.Notes and move it to PurchaseOrder.PoNumber. Notes is where we currenlty have the PONumbers.
I started with the Insert below, testing it out on one WellID. This is Inserting records from our DailyCosts table to the new PurchaseOrder table:
Insert Into PurchaseOrder (PoNumber,WellId,JObID,ID)
Select Distinct Cast(Notes As nvarchar(20)), WellID, JOBID,
DailyCosts.DailyCostID
From DailyCosts
Where WellID = '24A-23'
It affected 1973 rows (The Notes are in Ntext)
However, I need to update the other new tables because we need to see the actual PONumbers in the application.
This next Insert is Inserting records from our DailyCost table and new PurchaseOrder table (from above) to a new table called PurchaseOrderDailyCost
Insert Into PurchaseOrderDailyCost (WellID, JobID, ReportNo, AccountCode, PurchaseOrderID,ID,DailyCostSeqNo, DailyCostID)
Select Distinct DailyCosts.WellID,DailyCosts.JobID,DailyCosts.ReportNo,DailyCosts.AccountCode,
PurchaseOrder.ID,NEWID(),0,DailyCosts.DailyCostID
From DailyCosts join
PurchaseOrder ON DailyCosts.WellID = PurchaseOrder.WellID
Where DailyCosts.WellID = '24A-23'
Unfortunately, this produces 3,892,729 records. The Notes field contains the same list of PONumbers each day. This is by design so that the people inputting the data out in the field can easily track their PO numbers. The new PONumber column that we are moving the Notes to would store just unique POnumbers. I modified the query by replacing NEWID() with DailyCostID and the Join to ON DailyCosts.DailyCostID = PurchaseOrder.ID
This affected 1973 rows the same as the first Insert.
The next Insert looks like this:
Insert Into PurchaseOrderAccount (WellID, JobID, PurchaseOrderID, ID, AccountCode)
Select PurchaseOrder.WellID, PurchaseOrder.JobID, PurchaseOrder.ID, PurchaseOrderDailyCost.DailyCostID,PurchaseOrderDailyCost.AccountCode
From PurchaseOrder Inner Join
PurchaseOrderDailyCost ON PurchaseOrder.ID = PurchaseOrderDailyCost.DailyCostID
Where PurchaseOrder.WellID = '24A-23'
The page in the application now shows the PONumbers in the correct column. Everything looks like I want it to.
Unfortunately, it slows down the application to an unacceptable level. I need to figure out how to either modify my Insert or delete duplicate records. The problem is that there are multiple foreign key constraints. I have some more information below for reference.
This shows the application after the inserts. These are all duplicate records that I am hoping to elminate
Here is some additional information I received from the vendor about the tables:
-- add a new purchase order
INSERT INTO PurchaseOrder
(WellID, JobID, ID, PONumber, Amount, Description)
VALUES ('MyWell', 'MyJob', NEWID(), 'PO444444', 500.0, 'A new Purchase Order')
-- link a purchase order with id 'A356FBF4-A19B-4466-9E5C-20C5FD0E95C3' to a DailyCost record with SeqNo 0 and AccountCode 'MyAccount'
INSERT INTO PurchaseOrderDailyCost
(WellID, JobID, ReportNo, AccountCode, DailyCostSeqNo, PurchaseOrderID, ID)
VALUES ('MyWell', 'MyJob', 4, 'MyAccount', 0, 'A356FBF4-A19B-4466-9E5C-20C5FD0E95C3', NEWID())
-- link a purchase order with id 'A356FBF4-A19B-4466-9E5C-20C5FD0E95C3' to an account code 'MyAccount'
-- (i.e. make it choosable from the DailyCost PO-column dropdown for any DailyCost record whose account code is 'MyAccount')
INSERT INTO PurchaseOrderAccount
(WellID, JobID, PurchaseOrderID, ID, AccountCode)
VALUES ('MyWell', 'MyJob', 'A356FBF4-A19B-4466-9E5C-20C5FD0E95C3', NEWID(), 'MyAccount')
-- link a purchase order with id 'A356FBF4-A19B-4466-9E5C-20C5FD0E95C3' to an AFE No. 'MyAFENo'
-- (same behavior as with the account codes above)
INSERT INTO PurchaseOrderAFE
(WellID, JobID, PurchaseOrderID, ID, AFENo)
VALUES ('MyWell', 'MyJob', 'A356FBF4-A19B-4466-9E5C-20C5FD0E95C3', NEWID(), 'MyAFENo')
So it turns out I missed some simple joining principles. The better I get the more silly mistakes I seem to make. Basically, on my very first insert, I did not include a Group By. Adding this took my INSERT from 1973 to 93. Then on my next insert, I joined DailyCosts.Notes on PurchaseOrder.PONumber since these are the only records from DailyCosts I needed. This was previously INSERT 2 on my question. From there basically, everything came together. Two steps forward an one step back. Thanks to everyone that responded to this.
I have three joined tables Student, StudentTransportOrder and Transport in SQL Server 2012.
I have created a StudentActivity view for this.
In the StudentTransportOrder table, each student record has a unique TransportOrderID.
When transport is ordered, VehicleID this is recorded into the StudentTransportOrder table.
Unfortunately the same VehicleID has been entered for the same date and time for a student records.
The StudentActivity view already returns records based on where conditions, but I also need to remove the duplicate records, preferably keep the records where if a student has used transport on the same date and time, that only one distinct VehicleID is returned and preferably the where the transport type is TransportVehicle = Car
How can I amend the view , without deleting records from the main tables, also bring back records even if no transport has been ordered
Please help
Append
ROW_NUMBER() OVER(PARTITION BY StudentID,VehicleID ORDER BY (SELECT NULL)) AS PartitionedCount
... to your query and use a filter like WHERE PartitionedCount=1.
This will number your rows for each combination of Student and vehicle separately (you'll have to include the date or datetime probably).
You can use the (ORDER BY (SELECT NULL)) to force a car sorted on top...
UPDATE
As I do not know your actual tables here's a general example:
DECLARE #tbl TABLE(ID INT IDENTITY,GroupID INT,SomeValue VARCHAR(100));
INSERT INTO #tbl(GroupID,SomeValue) VALUES
(1,'val 1 for 1')
,(1,'val 2 for 1')
,(1,'val 3 for 1')
,(2,'val 1 for 2')
,(2,'val 2 for 2')
,(3,'val 1 for 3')
,(3,'val 2 for 3');
WITH Numbered AS
(
SELECT tbl.*
,ROW_NUMBER() OVER(PARTITION BY GroupID ORDER BY ID /*DESC*/) AS Number
FROM #tbl AS tbl
)
SELECT * FROM Numbered
WHERE Number=1
Try first without the WHERE. You will get all rows with partitioned numbering. Using the WHERE will reduce the output to the one with number =1.
It is on you to find a clever ORDER BY which brings your cars to the top (CASE will help you probably).
Just good to know: In my ORDER BY you find an inactive DESC. If you take away the /**/ you can use the same approach to find the last row to a given sort order.
Say I have two customer tables which have pretty much the same columns. One of them is a temporal one which periodically updates the other one. That is, updates and additions to the records are done to the temporal table only. Say they're names are CUSTOMER, and CUSTOMER_TEMP.
The tables got information like ID, NAME, LAST_NAME, and ADDRESS.
This temporal table has three extra fields, TEMP_ID, RECORD_TYPE, and DATE. The record type is used to record whether there was an addition or an update. So the thing is I need to select the latest record from both tables. That involves several cases
Main table has record, but temporal doesn't -> Select main table record.
Main table has no record, but temporal does -> Select latest temporal table record.
Main table has record and temporal has an add record -> Select temporal table record.
Main table has record and temporal table has update record -> Select temporal table record.
Main table has record and temporal table has add and update record. -> Select temporal table update record.
Main table has record and temporal table has various update records. -> Select latest temporal table update record.
Main table has record and temporal table has add record and various update records. -> Select latest temporal table update record.
Now, I don't know whether this is a good flow or not. I was just told to make the query, so I don't have access to the DB, I believe I could make suggestions though. The thing is My SLQ knowledge is not enough to build this query. I know there's an INNER_JOIN involved, as well as a filter by date, and probably and EXIST, to check whether the record exist or not in the CUSTOMER_TEMP table. But I don't quite know how to build it. I'm working on .Net And SQLServer. Any help on it is quite appreciated.
select m.*, 0 as [rn]
from main m
where not exists (select 1 from temp where temp.id = m.id)
union
select tt.*
from ( select temp.*
, row_number() over (partition by id order by RECORD_TYPE desc, date desc) as rn
from temp
-- join main
-- on temp.ID = main.ID
) tt
where tt.rn = 1
if update does not sort last then need to do a trick like in the answer from Tom H
;WITH CTE_Latest_Temporal AS
(
SELECT
id,
name,
..., -- Put the rest of your columns here
ROW_NUMBER OVER (PARTITION BY id
ORDER BY
CASE record_type
WHEN 'Update' THEN 0
ELSE 1
END, date DESC) AS row_num
FROM
Customer_Temp
)
SELECT
M.id,
CASE WHEN T.id IS NOT NULL THEN T.name ELSE M.name END AS name,
... -- Similar CASE statements for the rest of your columns
FROM
Customer M
LEFT OUTER JOIN CTE_Latest_Temporal T ON
T.id = M.id AND
T.row_num = 1
The CASE statements can be replaced by a simple COALESCE(T.column, M.column) for any columns that cannot be NULL. I had to use the CASE to cover situations where the row might exist in the temp table but the column might be NULL in the temp table, but have a value in the main table.