SQL Auto Increment a value with multiple inserts - sql

We have a SQL query being executed against a SQL Server 2008 DB.
INSERT INTO ListDetail(ListID, Sequence, CompName, CompAddress, Date)
(
SELECT
12345 AS 'ListID',
(MAX(ListDetail.Sequence) + 1) AUTO_INCREMENT as 'Sequence',
Company.Name AS 'CompName',
Company.Address AS 'CompAddress',
GETDATE() AS 'Date'
FROM Company
WHERE CompanyType = 3
)
We want to find the max Sequence from ListDetail table.. and select records from the Company table into ListDetail. But, we want to start with the next available Sequence value from ListDetail and then increment by 1 for each record inserted. The Sequence field in ListDetail is just a general INT field.
We do not have control over the database its-self... so created a new table or altering the existing one is not an option.

One option would be to use Row_Number() with a subquery that returns the max():
Simplified solution:
insert into ListDetail
select 12345, sq+row_number() over (order by (select null))
from company, (select max(sequence) sq from listdetail) t
SQL Fiddle Demo
INSERT INTO ListDetail(ListID, Sequence, CompName, CompAddress, Date)
SELECT
12345,
sq+row_number() over (order by (select null)),
Name,
Address,
GETDATE()
FROM Company, (select max(sequence) sq from listdetail) t
WHERE CompanyType = 3

A simple approach like this should work for you.
INSERT INTO ListDetail(ListID, Sequence, CompName, CompAddress, Date)
(
SELECT
12345,
(SELECT MAX(Sequence) + 1 FROM ListDetail),
Company.Name,
Company.Address,
GETDATE()
FROM Company
WHERE CompanyType = 3
)

Related

SQL query - how to aggregate only contiguous periods without lag or lead?

I'am still a novice and excuse for my english. You see that I have two persons with different periods of time and I want to aggregate the periods if they are contiguous. I don't know how to use for example the min() and max() functions related to the next line or the line before to compare the date. Or is there in easier way to solve this? I only have SQL Server 2008 R2 without the lag and lead-functions.
Sample data:
DECLARE #Table TABLE(
PersonID INT,
FROM date,
TO date
)
INSERT INTO #Table SELECT 1,'2011-01-01','2011-04-30'
INSERT INTO #Table SELECT 1,'2011-05-01','2011-08-31'
INSERT INTO #Table SELECT 1,'2011-09-01','2011-12-31'
INSERT INTO #Table SELECT 1,'2012-01-01','2012-03-31'
INSERT INTO #Table SELECT 2,'2011-03-01','2011-06-30'
INSERT INTO #Table SELECT 2,'2011-07-01','2011-10-31'
INSERT INTO #Table SELECT 2,'2013-01-01','2013-04-30'
INSERT INTO #Table SELECT 2,'2013-05-01','2013-08-31'
I expect something like this and look especially on PersonID 2:
PersonID FROM TO
1 , 2011-01-01 , 2012-03-31
2 , 2011-03-01 , 2011-10-31
2 , 2013-01-01 , 2013-08-31
This is a hard problem that would be made easier with cumulative sums and lag() or lead(). You can still do the work. I prefer to express it using correlated subqueries.
The logic starts by identifying which records are connected to the "next" record by an overlap. The following query uses this logic to define OverlapWithPrev.
select *
from (select t.*,
(select top 1 1
from t t2
where t2.personid = t.personid and
t2.fromd < t.fromd and
t2.tod >= dateadd(d, -1, t.fromd)
order by t2.fromd
) as OverlapWithPrev
from t
) t
This takes on the value of 1 when there is a previous record and NULL when there is not one.
Then with this information, the query then finds for each record the next record that is not overlapped with the previous one (and on the same person). When you have a sequence of overlapping records, then all will have the same such next record, and the next record is used for aggregation.
Here is the full query:
with tp as
(select *
from (select t.*,
(select top 1 1
from t t2
where t2.personid = t.personid and
t2.fromd < t.fromd and
t2.tod >= dateadd(d, -1, t.fromd)
order by t2.fromd
) as OverlapWithPrev
from t
) t
)
select personid, min(fromd) as fromd, max(tod) as tod
from (select tp.*,
(select top 1 fromd
from tp tp2
where tp2.OverlapWithPrev is null and
tp2.personid = tp.personid and
tp2.fromd > tp.fromd
) as NextFromD
from tp
) tp
group by personid, NextFromD;
Here is a SQLFiddle to show how it works.

Add an incremental number in a field in INSERT INTO SELECT query in SQL Server

I have an INSERT INTO SELECT query. In the SELECT statement I have a subquery in which I want to add an incremental number in a field.
This query will work fine if my SELECT query and returns only one record, But if it returns multiple rows it inserts the same number in the incremental field for all those rows.
Is there any way to restrict it to add an incremental number every time?
INSERT INTO PM_Ingrediants_Arrangements_Temp
(AdminID,ArrangementID,IngrediantID,Sequence)
(SELECT
#AdminID, #ArrangementID, PM_Ingrediants.ID,
(SELECT
MAX(ISNULL(sequence,0)) + 1
FROM
PM_Ingrediants_Arrangements_Temp
WHERE
ArrangementID=#ArrangementID)
FROM
PM_Ingrediants
WHERE
PM_Ingrediants.ID IN (SELECT
ID
FROM
GetIDsTableFromIDsList(#IngrediantsIDs))
)
You can use the row_number() function for this.
INSERT INTO PM_Ingrediants_Arrangements_Temp(AdminID, ArrangementID, IngrediantID, Sequence)
SELECT #AdminID, #ArrangementID, PM_Ingrediants.ID,
row_number() over (order by (select NULL))
FROM PM_Ingrediants
WHERE PM_Ingrediants.ID IN (SELECT ID FROM GetIDsTableFromIDsList(#IngrediantsIDs)
)
If you want to start with the maximum already in the table then do:
INSERT INTO PM_Ingrediants_Arrangements_Temp(AdminID, ArrangementID, IngrediantID, Sequence)
SELECT #AdminID, #ArrangementID, PM_Ingrediants.ID,
coalesce(const.maxs, 0) + row_number() over (order by (select NULL))
FROM PM_Ingrediants cross join
(select max(sequence) as maxs from PM_Ingrediants_Arrangement_Temp) const
WHERE PM_Ingrediants.ID IN (SELECT ID FROM GetIDsTableFromIDsList(#IngrediantsIDs)
)
Finally, you can just make the sequence column an auto-incrementing identity column. This saves the need to increment it each time:
create table PM_Ingrediants_Arrangement_Temp ( . . .
sequence int identity(1, 1) -- and might consider making this a primary key too
. . .
)

Find last row in group by query-SQL Server

I have table in SQL Server. I want to find last row in each group. I tried with the following query, but it does not return exact result. ID column is PK and other columns are set to NOT NULL.
select ID, Name FROM
(select ID, Name, max(ID) over (partition by Name) as MAX_ID
from Customer) x where ID= MAX_ID
To be more clear. I have 2 queries.First:
ALTER PROCEDURE [dbo].[Ramiz_Musterija_RowNum]
#Datum DATE,
#BrojKamiona INT
AS SET NOCOUNT ON
SELECT Ime,MusterijaID,RowNum=ROW_NUMBER() OVER(ORDER BY Ime)FROM Musterije
WHERE Datum=#Datum AND BrojKamiona=#BrojKamiona GROUP BY Ime,MusterijaID
And second one:
ALTER PROCEDURE [dbo].[Ramiz_Musterija_FindLast]
#Datum DATE,
#BrojKamiona INT
AS SET NOCOUNT ON
SELECT a.* from Musterije a
JOIN (SELECT Ime, MAX(MusterijaID) AS MAXID FROM Musterije GROUP BY Ime) AS b
ON a.MusterijaID = b.MAXID AND a.Datum=#Datum AND a.BrojKamiona=#BrojKamiona
Then LINQ query:
var rowNumList = from f in customerFindLastList
join r in customerRowNumList
on f.MusterijaID equals r.MusterijaID
select new { r.RowNum };
I am trying to find last row in each row,then match this 2 queries on MusterijaID column.
Any help regarding this would be appreciated.
This is output of one group. Now, problem is that these two queries are matched on "4250" MusterijaID, but I need to match queries on "4229".
Ime MusterijaID
100//1 4246
100//1 4247
100//1 4248
100//1 4249
100//1 4250
100//1 4229
select ID, Name
FROM (select ID, Name, -- add other columns here
ROW_NUMBER() over (partition by Name ORDER BY ID DESC) as MAX_ID
from Customer) x
WHERE MAX_ID = 1

Row with the highest ID

You have three fields ID, Date and Total. Your table contains multiple rows for the same day which is valid data however for reporting purpose you need to show only one row per day. The row with the highest ID per day should be returned the rest should be hidden from users (not returned).
To better picture the question below is sample data and sample output:
ID, Date, Total
1, 2011-12-22, 50
2, 2011-12-22, 150
The correct result is:
2, 2012-12-22, 150
The correct output is single row for 2011-12-22 date and this row was chosen because it has the highest ID (2>1)
Assuming that you have a database that supports window functions, and that the date column is indeed just date (and not datetime), then something like:
SELECT
* --TODO - Pick columns
FROM
(
SELECT ID,[Date],Total,ROW_NUMBER() OVER (PARTITION BY [Date] ORDER BY ID desc) rn
FROM [Table]
) t
WHERE
rn = 1
Should produce one row per day - and the selected row for any given day is that with the highest ID value.
SELECT *
FROM table
WHERE ID IN ( SELECT MAX(ID)
FROM table
GROUP BY Date )
This will work.
SELECT *
FROM tableName a
INNER JOIN
(
SELECT `DATE`, MAX(ID) maxID
FROM tableName
GROUP BY `DATE`
) b ON a.id = b.MaxID AND
a.`date` = b.`date`
SQLFiddle Demo
Probably
SELECT * FROM your_table ORDER BY ID DESC LIMIT 1
Select MAX(ID),Data,Total from foo
for MySQL
Another simple way is
SELECT TOP 1 * FROM YourTable ORDER BY ID DESC
And, I think this is the most simple way!
SELECT * FROM TABLE_SUM S WHERE S.ID =
(
SELECT MAX(ID) FROM TABLE_SUM
WHERE CDATE = GG.CDATE
GROUP BY CDATE
)

Select a Column in SQL not in Group By

I have been trying to find some info on how to select a non-aggregate column that is not contained in the Group By statement in SQL, but nothing I've found so far seems to answer my question. I have a table with three columns that I want from it. One is a create date, one is a ID that groups the records by a particular Claim ID, and the final is the PK. I want to find the record that has the max creation date in each group of claim IDs. I am selecting the MAX(creation date), and Claim ID (cpe.fmgcms_cpeclaimid), and grouping by the Claim ID. But I need the PK from these records (cpe.fmgcms_claimid), and if I try to add it to my select clause, I get an error. And I can't add it to my group by clause because then it will throw off my intended grouping. Does anyone know any workarounds for this? Here is a sample of my code:
Select MAX(cpe.createdon) As MaxDate, cpe.fmgcms_cpeclaimid
from Filteredfmgcms_claimpaymentestimate cpe
where cpe.createdon < 'reportstartdate'
group by cpe.fmgcms_cpeclaimid
This is the result I'd like to get:
Select MAX(cpe.createdon) As MaxDate, cpe.fmgcms_cpeclaimid, cpe.fmgcms_claimid
from Filteredfmgcms_claimpaymentestimate cpe
where cpe.createdon < 'reportstartdate'
group by cpe.fmgcms_cpeclaimid
The columns in the result set of a select query with group by clause must be:
an expression used as one of the group by criteria , or ...
an aggregate function , or ...
a literal value
So, you can't do what you want to do in a single, simple query. The first thing to do is state your problem statement in a clear way, something like:
I want to find the individual claim row bearing the most recent
creation date within each group in my claims table
Given
create table dbo.some_claims_table
(
claim_id int not null ,
group_id int not null ,
date_created datetime not null ,
constraint some_table_PK primary key ( claim_id ) ,
constraint some_table_AK01 unique ( group_id , claim_id ) ,
constraint some_Table_AK02 unique ( group_id , date_created ) ,
)
The first thing to do is identify the most recent creation date for each group:
select group_id ,
date_created = max( date_created )
from dbo.claims_table
group by group_id
That gives you the selection criteria you need (1 row per group, with 2 columns: group_id and the highwater created date) to fullfill the 1st part of the requirement (selecting the individual row from each group. That needs to be a virtual table in your final select query:
select *
from dbo.claims_table t
join ( select group_id ,
date_created = max( date_created )
from dbo.claims_table
group by group_id
) x on x.group_id = t.group_id
and x.date_created = t.date_created
If the table is not unique by date_created within group_id (AK02), you you can get duplicate rows for a given group.
You can do this with PARTITION and RANK:
select * from
(
select MyPK, fmgcms_cpeclaimid, createdon,
Rank() over (Partition BY fmgcms_cpeclaimid order by createdon DESC) as Rank
from Filteredfmgcms_claimpaymentestimate
where createdon < 'reportstartdate'
) tmp
where Rank = 1
The direct answer is that you can't. You must select either an aggregate or something that you are grouping by.
So, you need an alternative approach.
1). Take you current query and join the base data back on it
SELECT
cpe.*
FROM
Filteredfmgcms_claimpaymentestimate cpe
INNER JOIN
(yourQuery) AS lookup
ON lookup.MaxData = cpe.createdOn
AND lookup.fmgcms_cpeclaimid = cpe.fmgcms_cpeclaimid
2). Use a CTE to do it all in one go...
WITH
sequenced_data AS
(
SELECT
*,
ROW_NUMBER() OVER (PARITION BY fmgcms_cpeclaimid ORDER BY CreatedOn DESC) AS sequence_id
FROM
Filteredfmgcms_claimpaymentestimate
WHERE
createdon < 'reportstartdate'
)
SELECT
*
FROM
sequenced_data
WHERE
sequence_id = 1
NOTE: Using ROW_NUMBER() will ensure just one record per fmgcms_cpeclaimid. Even if multiple records are tied with the exact same createdon value. If you can have ties, and want all records with the same createdon value, use RANK() instead.
You can join the table on itself to get the PK:
Select cpe1.PK, cpe2.MaxDate, cpe1.fmgcms_cpeclaimid
from Filteredfmgcms_claimpaymentestimate cpe1
INNER JOIN
(
select MAX(createdon) As MaxDate, fmgcms_cpeclaimid
from Filteredfmgcms_claimpaymentestimate
group by fmgcms_cpeclaimid
) cpe2
on cpe1.fmgcms_cpeclaimid = cpe2.fmgcms_cpeclaimid
and cpe1.createdon = cpe2.MaxDate
where cpe1.createdon < 'reportstartdate'
Thing I like to do is to wrap addition columns in aggregate function, like max().
It works very good when you don't expect duplicate values.
Select MAX(cpe.createdon) As MaxDate, cpe.fmgcms_cpeclaimid, MAX(cpe.fmgcms_claimid) As fmgcms_claimid
from Filteredfmgcms_claimpaymentestimate cpe
where cpe.createdon < 'reportstartdate'
group by cpe.fmgcms_cpeclaimid
What you are asking, Sir, is as the answer of RedFilter.
This answer as well helps in understanding why group by is somehow a simpler version or partition over:
SQL Server: Difference between PARTITION BY and GROUP BY
since it changes the way the returned value is calculated and therefore you could (somehow) return columns group by can not return.
You can use as below,
Select X.a, X.b, Y.c from (
Select X.a as a, sum (b) as sum_b from name_table X
group by X.a)X
left join from name_table Y on Y.a = X.a
Example;
CREATE TABLE #products (
product_name VARCHAR(MAX),
code varchar(3),
list_price [numeric](8, 2) NOT NULL
);
INSERT INTO #products VALUES ('paku', 'ACE', 2000)
INSERT INTO #products VALUES ('paku', 'ACE', 2000)
INSERT INTO #products VALUES ('Dinding', 'ADE', 2000)
INSERT INTO #products VALUES ('Kaca', 'AKB', 2000)
INSERT INTO #products VALUES ('paku', 'ACE', 2000)
--SELECT * FROM #products
SELECT distinct x.code, x.SUM_PRICE, product_name FROM (SELECT code, SUM(list_price) as SUM_PRICE From #products
group by code)x
left join #products y on y.code=x.code
DROP TABLE #products