SQL Server : auto-increment column in function of two columns values - sql-server

I want to produce a similar table that this table below.
In the first time, this table is create by another program but I must insert a new rows when an images is added.
For this, I have try this request but the select is done upstream of the insert and the Max function is useless.
#idart contains a table with multiple CODE and ID_IMG but without ORDER number.
INSERT INTO [NOMENC_ARTICLES_IMAGES]
SELECT
I.CODE, I.ID As ID_IMG,
CASE
WHEN (SELECT MAX(AI.ORDRE) FROM [NOMENC_ARTICLES_IMAGES] AS AI
WHERE AI.CODE = A.CODE) IS NULL
THEN 0
ELSE (SELECT MAX(AI.ORDRE) FROM [NOMENC_ARTICLES_IMAGES] AS AI
WHERE AI.CODE = A.CODE) + 1
END AS ORDER
FROM
#idart AS I
LEFT JOIN
[NOMENC_ARTICLES_IMAGES] AS A ON A.CODE = I.CODE
Could you help me to increment the ORDER column in terms of CODE and ID_IMG?
EDIT :
In [NOMENC_ARTICLES_IMAGES] I have :
And I want to add 1, 2, x value contains in #idart.
For exemple :
#idart :
The expected result after insert :
I hope that with this example, you will better understand my need

I think I've find the solution based on the answer of casenonsensitive :
INSERT INTO [NOMENC_ARTICLES_IMAGES]
SELECT I.CODE, I.ID As ID_IMG,
row_number() over (partition by I.CODE order by I.ID) +
CASE WHEN A.ORDER IS NULL THEN -1 ELSE A.ORDER END As ORDER
FROM
#idart AS I
LEFT JOIN
(SELECT AI.CODE, MAX(AI.ORDER) As ORDER FROM [NOMENC_ARTICLES_IMAGES] As AI GROUP BY AI.CODE) AS A ON A.CODE = I.CODE
Thanks for all !

Use an analytical function like this:
INSERT INTO [NOMENC_ARTICLES_IMAGES]
select I.CODE, I.ID As ID_IMG,
row_number() over (partition by I.CODE order by I.ID)
+ (select isnull(max(order), 0) from [NOMENC_ARTICLES_IMAGES] AS A ON A.CODE = I.CODE)
As ORDER
FROM
#idart AS I
But pay attention, that you're always getting the highest order for the highest I.ID per I.CODE. In some cases that works, in others I.ID would not have to be strictly growing. Meaning the newest images wouldn't get the biggest ORDER's

Related

Display of online users on the system

I don't know exactly where I'm wrong, but I need a list of all the workers who are currently at work (for the current day), this is my sql query:
SELECT
zp.ID,
zp.USER_ID,
zp.Arrive,
zp.Deppart,
zp.DATUM
FROM time_recording as zp
INNER JOIN personal AS a on zp.USER_ID, = zp.USER_ID,
WHERE zp.Arrive IS NOT NULL
AND zp.Deppart IS NULL
AND zp.DATUM = convert(date, getdate())
ORDER BY zp.ID DESC
this is what the data looks like with my query:
For me the question is, how can I correct my query so that I only get the last Arrive time for the current day for each user?
In this case to get only these values:
Try this below script using ROW_NUMBER as below-
SELECT * FROM
(
SELECT zp.ID, zp.USER_ID, zp.Arrive, zp.Deppart, zp.DATUM,
ROW_NMBER() OVER(PARTITION BY zp.User_id ORDER BY zp.Arrive DESC) RN
FROM time_recording as zp
INNER JOIN personal AS a
on zp.USER_ID = zp.USER_ID
-- You need to adjust above join relation as both goes to same table
-- In addition, as you are selecting nothing from table personal, you can drop the total JOIN part
WHERE zp.Arrive IS NOT NULL
AND zp.Deppart IS NULL
AND zp.DATUM = convert(date, getdate())
)A
WHERE RN =1
you can try this:
SELECT DISTINCT
USER_ID,
LAR.LastArrive
FROM time_recording as tr
CROSS APPLY (
SELECT
MAX(Arrive) as LastArrive
FROM time_recording as ta
WHERE
tr.USER_ID = ta.USER_ID AND
ta.Arrive IS NOT NULL
) as LAR

Select Newest Record

I have two tables (Journal and Incident). Each incident may have more than one journal entry. I want to select the record and the most recent journal data.
The where section at the bottom is what filters the incidents I want to see. Of those, I want the journal values associated with the most recent journal entry.
This is an amalgam of code I've found on here, but when I run it I get a "Query execution failed for dataset 'DataSet1'. Unfortunately, I don't have access to the log files to see if there are clues there.
Any help is appreciated. I think I may have it nested wrong.
SELECT
b.IncidentNumber
,a.Subject
,a.CreatedDateTime
,b.SubCategory
,b.EffectiveDueDate
,b.NextActionDate
,b.ProfileFullName
FROM
(
SELECT
b.IncidentNumber
,a.Subject
,a.CreatedDateTime
,rn = row_number() OVER (PARTITION by b.IncidentNumber ORDER BY
a.CreatedDateTime DESC)
,b.SubCategory
,b.EffectiveDate
,b.NextActionDate
,b.ProfileFullName
FROM
Journal a LEFT JOIN Incident b ON
a.ParentRecordNumber = b.IncidentNumber
WHERE a.Category LIKE '%KANBAN%'
AND (b.Status LIKE' %Waiting%' OR b.status LIKE '%Active%')
AND b.SubCategory <> 'User Termination'
AND b.SubCategory <> 'Res Temp Termination'
AND a.Subject LIKE 'UP |%'
) X
WHERE rn = 1
Few things:
Outer most selected values should be from inline view aliased "X" No a. or b. as those alias only are in scope to the in inner query. (except when using coorlation but that's 1 level only I believe)
You either need to right join instead of left or change the order of the tables. I believe you want all incidents and the MOST recent Journal; not all journals and the related incident if one exists. thus I changed the order.
Lastly when using outer joins, you can only put limits on the all records table of the outer join. Where clause criteria the OUTER joined tables will cause the null records generated by the outer join to be excluded. To resolve this you must move the limiting criteria to the join or use an 'or' statement to check for null (it's cleaner to move it to the join). Think of it is applying the limit before the join occurs so Null records from incident are kept. otherwise the outer join simulates a INNER JOIN by excluding those records not in both tables (or in this case in incident but not in journal)
.
SELECT x.IncidentNumber --alias x not a/b as the from is aliased as 'X'
, x.Subject
, x.CreatedDateTime
, x.SubCategory
, x.EffectiveDueDate
, x.NextActionDate
, x.ProfileFullName
FROM (SELECT b.IncidentNumber
, a.Subject
, a.CreatedDateTime
, rn = row_number() OVER (PARTITION by b.IncidentNumber
ORDER BY a.CreatedDateTime DESC)
, b.SubCategory
, b.EffectiveDate
, b.NextActionDate
, b.ProfileFullName
FROM Incident b --switched the order I think you want all incidents and if a journal exists it's value.
LEFT JOIN Journal a
ON a.ParentRecordNumber = b.IncidentNumber
-- Since A is on the if match found to B, we need to move this to the join or we lose the records created from the outer join.
AND a.Category LIKE '%KANBAN%'
AND a.Subject LIKE 'UP |%'
--moved some where clause criteria to the join Since B is on the "all records side" of the outer join we can leave B in the where clause.
WHERE (b.Status LIKE' %Waiting%' OR b.status LIKE '%Active%')
AND b.SubCategory <> 'User Termination'
AND b.SubCategory <> 'Res Temp Termination') X
WHERE rn = 1
If you are not getting records from here, then I'd start removing some of the limiting criteria to ensure the query is functioning as desired and then add back in limits to see what's causing no records to be found.
I've finally got this report working as expected. It took a few iterations to get the query working, but it's doing what it should, now. Many thanks for your assist. I would have never gotten there without it!
SELECT x.IncidentNumber
, x.Subject
, x.CreatedDateTime
, x.SubCategory
, x.ProfileFullName
, x.PropertyNumber
, x.Status
, x.EffectiveDueDate
FROM (SELECT b.IncidentNumber
, a.Subject
, a.CreatedDateTime
, rn = row_number() OVER (PARTITION by b.IncidentNumber
ORDER BY a.CreatedDateTime DESC)
, b.SubCategory
, b.ProfileFullName
, b.PropertyNumber
, b.Status
, b.EffectiveDueDate
FROM Incident b
RIGHT JOIN Journal a
ON a.ParentRecordNumber = b.IncidentNumber
AND a.Category LIKE '%KANBAN%'
AND a.Subject LIKE 'UP |%'
WHERE (b.Status LIKE' %Waiting%' OR b.status LIKE '%Active%')
) x
WHERE rn = 1

Calculated summary field based on child table

I have two tables, Order and OrderItem. There is a one-to-many relationship on Order.Order_ID=OrderItem.Order_ID
I want a query to return a list showing the status of each Order, COMPLETE or INCOMPLETE.
A COMPLETE Order is defined as one where all the related OrderItem records have a non-NULL, non-empty value in the OrderItem.Delivery_ID field.
This is what I have so far:
SELECT Order.Order_ID, 'INCOMPLETE' AS Order_status
FROM Order
WHERE EXISTS
(SELECT *
FROM OrderItem
WHERE OrderItem.Order_ID=Order.Order_ID
AND (OrderItem.Delivery_ID IS NULL OR OrderItem.Delivery_ID=''))
UNION
SELECT Order.Order_ID, 'COMPLETE' AS Order_status
FROM Order
WHERE NOT EXISTS
(SELECT *
FROM OrderItem
WHERE OrderItem.Order_ID=Order.Order_ID
AND (OrderItem.Delivery_ID IS NULL OR OrderItem.Delivery_ID=''))
ORDER BY Order_ID DESC
It works, but runs a bit slow. Is there a better way?
(N.B. I've restated the problem for clarity, actual table and field names are different)
I would suggest you have a column status on your Order table and update the status to complete when all order items get delivered.
It will make simple your query to get status as well improve performance.
Put it into a subquery to try to make the case statement less confusing:
SELECT Order_ID,
CASE WHEN incomplete_count > 0 THEN 'INCOMPLETE' ELSE 'COMPLETE' END
AS Order_status
FROM ( SELECT o.Order_ID
,SUM( CASE WHEN OrderItem.Delivery_ID IS NULL OR OrderItem.Delivery_ID='' THEN 1 ELSE 0 END )
AS incomplete_count
FROM Order o
INNER JOIN OrderItem i ON (i.Order_ID = o.Order_ID)
GROUP by o.Order_ID
) x
ORDER BY ORder_ID DESC
The idea is to keep a counter every time you encounter a null item. If the sum is 0, there were no empty order items.
Try this one -
SELECT
o.Order_ID
, Order_status =
CASE WHEN ot.Order_ID IS NULL
THEN 'COMPLETE'
ELSE 'INCOMPLETE'
END
FROM dbo.[Order] o
LEFT JOIN (
SELECT DISTINCT ot.Order_ID
FROM dbo.OrderItem ot
WHERE ISNULL(ot.Delivery_ID, '') = ''
) ot ON ot.Order_ID = o.Order_ID

TSQL optimizing code for NOT IN

I inherit an old SQL script that I want to optimize but after several tests, I must admit that all my tests only creates huge SQL with repetitive blocks. I would like to know if someone can propose a better code for the following pattern (see code below). I don't want to use temporary table (WITH). For simplicity, I only put 3 levels (table TMP_C, TMP_D and TMP_E) but the original SQL have 8 levels.
WITH
TMP_A AS (
SELECT
ID,
Field_X
FROM A
TMP_B AS(
SELECT DISTINCT
ID,
Field_Y,
CASE
WHEN Field_Z IN ('TEST_1','TEST_2') THEN 'CATEG_1'
WHEN Field_Z IN ('TEST_3','TEST_4') THEN 'CATEG_2'
WHEN Field_Z IN ('TEST_5','TEST_6') THEN 'CATEG_3'
ELSE 'CATEG_4'
END AS CATEG
FROM B
INNER JOIN TMP_A
ON TMP_A.ID=TMP_B.ID),
TMP_C AS (
SELECT DISTINCT
ID,
CATEG
FROM TMP_B
WHERE CATEG='CATEG_1'),
TMP_D AS (
SELECT DISTINCT
ID,
CATEG
FROM TMP_B
WHERE CATEG='CATEG_2' AND ID NOT IN (SELECT ID FROM TMP_C)),
TMP_E AS (
SELECT DISTINCT
ID,
CATEG
FROM TMP_B
WHERE CATEG='CATEG_3'
AND ID NOT IN (SELECT ID FROM TMP_C)
AND ID NOT IN (SELECT ID FROM TMP_D))
SELECT * FROM TMP_C
UNION
SELECT * FROM TMP_D
UNION
SELECT * FROM TMP_E
Many thanks in advance for your help.
First off, select DISTINCT will prevent duplicates from the result set, so you are overworking the condition. By adding the "WITH" definitions and trying to nest their use makes it more confusing to follow. The data is ultimately all coming from the "B" table where also has key match in "A". Lets start with just that... And since you are not using anything from the (B)Field_Y or (A)Field_X in your result set, don't add them to the mix of confusion.
SELECT DISTINCT
B.ID,
CASE WHEN B.Field_Z IN ('TEST_1','TEST_2') THEN 'CATEG_1'
WHEN B.Field_Z IN ('TEST_3','TEST_4') THEN 'CATEG_2'
WHEN B.Field_Z IN ('TEST_5','TEST_6') THEN 'CATEG_3'
ELSE 'CATEG_4'
END AS CATEG
FROM
B JOIN A ON B.ID = A.ID
WHERE
B.Field_Z IN ( 'TEST_1', 'TEST_2', 'TEST_3', 'TEST_4', 'TEST_5', 'TEST_6' )
The where clause will only include those category qualifying values you want and still have the results per each category.
Now, if you actually needed other values from your "Field_Y" or "Field_X", then that would generate a different query. However, your Tmp_C, Tmp_D and Tmp_E are only asking for the ID and CATEG columns anyhow.
This may perform better
SELECT DISTINCT B.ID, 'CATEG_1'
FROM
B JOIN A ON B.ID = A.ID
WHERE
B.Field_Z IN ( 'TEST_1', 'TEST_2')
UNION
SELECT DISTINCT B.ID, 'CATEG_2'
FROM
B JOIN A ON B.ID = A.ID
WHERE
B.Field_Z IN ( 'TEST_3', 'TEST_4')
...

Join subquery with min

I'm pulling my hair out over a subquery that I'm using to avoid about 100 duplicates (out of about 40k records). The records that are duplicated are showing up because they have 2 dates in h2.datecreated for a valid reason, so I can't just scrub the data.
I'm trying to get only the earliest date to return. The first subquery (that starts with "select distinct address_id", with the MIN) works fine on it's own...no duplicates are returned. So it would seem that the left join (or just plain join...I've tried that too) couldn't possibly see the second h2.datecreated, since it doesn't even show up in the subquery. But when I run the whole query, it's returning 2 values for some ipc.mfgid's, one with the h2.datecreated that I want, and the other one that I don't want.
I know it's got to be something really simple, or something that just isn't possible. It really seems like it should work! This is MSSQL. Thanks!
select distinct ipc.mfgid as IPC, h2.datecreated,
case when ad.Address is null
then ad.buildingname end as Address, cast(trace.name as varchar)
+ '-' + cast(trace.Number as varchar) as ONT,
c.ACCOUNT_Id,
case when h.datecreated is not null then h.datecreated
else h2.datecreated end as Install
from equipmentjoin as ipc
left join historyjoin as h on ipc.id = h.EQUIPMENT_Id
and h.type like 'add'
left join circuitjoin as c on ipc.ADDRESS_Id = c.ADDRESS_Id
and c.GRADE_Code like '%hpna%'
join (select distinct address_id, equipment_id,
min(datecreated) as datecreated, comment
from history where comment like 'MAC: 5%' group by equipment_id, address_id, comment)
as h2 on c.address_id = h2.address_id
left join (select car.id, infport.name, carport.number, car.PCIRCUITGROUP_Id
from circuit as car (NOLOCK)
join port as carport (NOLOCK) on car.id = carport.CIRCUIT_Id
and carport.name like 'lead%'
and car.GRADE_Id = 29
join circuit as inf (NOLOCK) on car.CCIRCUITGROUP_Id = inf.PCIRCUITGROUP_Id
join port as infport (NOLOCK) on inf.id = infport.CIRCUIT_Id
and infport.name like '%olt%' )
as trace on c.ccircuitgroup_id = trace.pcircuitgroup_id
join addressjoin as ad (NOLOCK) on ipc.address_id = ad.id
The typical approach to only getting the lowest row is one of the following. You didn't bother to specify what version of SQL Server you're using, what you want to do with ties, and I have little interest to try to work this into your complex query, so I'll show you an abstract simplification for different versions.
SQL Server 2000
SELECT x.grouping_column, x.min_column, x.other_columns ...
FROM dbo.foo AS x
INNER JOIN
(
SELECT grouping_column, min_column = MIN(min_column)
FROM dbo.foo GROUP BY grouping_column
) AS y
ON x.grouping_column = y.grouping_column
AND x.min_column = y.min_column;
SQL Server 2005+
;WITH x AS
(
SELECT grouping_column, min_column, other_columns,
rn = ROW_NUMBER() OVER (ORDER BY min_column)
FROM dbo.foo
)
SELECT grouping_column, min_column, other_columns
FROM x
WHERE rn = 1;
This subqery:
select distinct address_id, equipment_id,
min(datecreated) as datecreated, comment
from history where comment like 'MAC: 5%' group by equipment_id, address_id, comment
Probably will return multiple rows because the comment is not guaranteed to be the same.
Try this instead:
CROSS APPLY (
SELECT TOP 1 H2.DateCreated, H2.Comment -- H2.Equipment_id wasn't used
FROM History H2
WHERE
H2.Comment LIKE 'MAC: 5%'
AND C.Address_ID = H2.Address_ID
ORDER BY DateCreated
) H2
Switch that to OUTER APPLY in case you want rows that don't have a matching desired history entry.

Resources