Add one with same foreign key at row sql server - sql-server

I have a problem on sql server.
How to get running number from foreign key in one time select data from table?
example :
I have one table such as
-----------------
| id | pid | desc |
-----------------
| 1 | 1 | a |
| 2 | 1 | b |
| 3 | 1 | c |
| 4 | 2 | d |
| 5 | 2 | e |
| 6 | 2 | f |
| 7 | 2 | g |
| 8 | 3 | h |
| 9 | 3 | i |
| 10 | 1 | j |
| 11 | 1 | k |
-----------------
I want to get result as below
------------------------
| id | pid | desc | rec |
------------------------
| 1 | 1 | a | 1 |
| 2 | 1 | b | 2 |
| 3 | 1 | c | 3 |
| 4 | 2 | d | 1 |
| 5 | 2 | e | 2 |
| 6 | 2 | f | 3 |
| 7 | 2 | g | 4 |
| 8 | 3 | h | 1 |
| 9 | 3 | i | 2 |
| 10 | 1 | j | 4 |
| 11 | 1 | K | 5 |
------------------------
In above tables foreign key ('pid') Column has values 1 to 3 in different row numbers.
I tried to get the running number from each 'pid' field name.
I havn't found any way to do this,
Can I do that? Can some one help me? am still newbie at sql server

Try this
SELECT
id,
pid,
[desc],
Row_Number() OVER (PARTITION BY pid ORDER BY id) AS rec
FROM <yourtable>
ORDER BY id

You can use Ranking function in SQL Server 2005+ to accomplish that,
So here is your query
Select Row_Number() over (partition by pid order by id) as rec , * from Table

Related

MSSQL recursive query to find furthest parent

We have a db structure where each company has a parent company defined. What we want to do is walk up the structure from a given start point until the next 'most-parent' company is found and pull what that users assignment is to that 'most-parent' company. Below is a mock example.
+===================+ +=======+ +=============+
| Company | | User | | UserAccess |
+===================+ +=======+ +=============+
| id | | id | | id |
| Name | | Name | | fkUserId |
| fkParentCompanyId | +=======+ | fkCompanyId |
+===================+ | AccessLevel |
+=============+
+=======+
|Company|
+=============================================+
| id | Name | fkParentCompanyId |
+=============================================+
| 1 | ABC Corp | 1 |
| 2 | Outside Company | 1 |
| 3 | Inside Company | 1 |
| 4 | My Company | 3 |
| 5 | Other LLC | 4 |
| 6 | Yet Another Comp | 5 |
+=============================================+
+====+
|User|
+======================+
| id | Name |
+======================+
| 1 | Mike |
| 2 | Jackie |
| 3 | Sam |
+======================+
+==========+
|UserAccess|
+=================================================+
| id | fkUserId | fkCompanyId | AccessLevel |
+=================================================+
| 1 | 1 | 1 | Administrator |
| 2 | 2 | 1 | User |
| 3 | 3 | 1 | Administrator |
| 4 | 3 | 3 | Parent |
| 5 | 3 | 4 | Parent |
| 6 | 3 | 5 | Parent |
| 7 | 3 | 6 | Parent |
+=================================================+
So take 'Same', user.id == 3. I want to do a query that finds the nearest "not-Parent" relationship when given a starting Company.id along with Sam's User.id. Next is what I'm looking to get from the given inputs.
Inputs: User.id = 3, Company.id = 6
Output: Administrator
Inputs: User.id = 3, Company.id = 5
Output: Administrator
Inputs: User.id = 3, Company.id = 4
Output: Administrator
Inputs: User.id = 2, Company.id = 1
Output: User
I've been looking at recursive queries using the CTE model, having some difficulty understanding what's it's really doing and thus not yet able to translate that model into something that would work for the above example.
Any guidance would be greatly appreciated.
Update
Been working on CTE in SSMS and feel like I'm getting close... Here is an example query that I'm trying, but not getting the result I expect...
Here I'm trying to do a recursive CTE on Sam # "Yet Another Comp". What I want is a list of Sams access up the chain.
with cte(UserId, CompanyId, UserAccess, ParentCompanyId)
as
(
select
[UserId],
[CompanyId],
[UserAccess],
[ParentCompanyId]
from [UserAccess]
where [UserId] = 3 and [CompanyId] = 6
union all
select
[UserAccess].[UserId],
[UserAccess].[CompanyId],
[UserAccess].[AccessLevel],
[cte].[ParentCompanyId]
from [UserAccess]
join [cte] on [UserAccess].[ParentCompanyId] = [cte].[CompanyId]
where [UserAccess].[UserId] = 3 [UserAccess].[CompanyId] != 6
)
select * from cte
I'm expecting this:
+===+
|cte|
+==========================================================+
| UserId | CompanyId | UserAccess | ParentCompanyId |
+==========================================================+
| 3 | 6 | Parent | 5 |
| 3 | 5 | Parent | 4 |
| 3 | 4 | Parent | 3 |
| 3 | 3 | Parent | 1 |
| 3 | 1 | Administrator | 1 |
+==========================================================+
But what I'm actually getting is this:
+===+
|cte|
+==========================================================+
| UserId | CompanyId | UserAccess | ParentCompanyId |
+==========================================================+
| 3 | 6 | Parent | 5 |
+==========================================================+
The recursive query isn't pulling additional rows into the table. So I commented out the where statement on the recursive query, expecting to get a max recursion error and see a blip of all of the results. But no, still just get the single row back.

SQL-Server Closure table query

I need a hierarchy for my database and decided to use the closure table model. The hierarchy tables have the usual structure, like this:
locations table
+----+---------+
| id | name |
+----+---------+
| 1 | Europe |
| 2 | France |
| 3 | Germany |
| 4 | Spain |
| 5 | Paris |
| 6 | Nizza |
| 7 | Berlin |
| 8 | Munich |
| 9 | Madrid |
+----+---------+
CREATE TABLE locations (
id int IDENTITY(1,1) PRIMARY KEY,
name varchar(30)
)
lacations_relation table
+----+--------+--------+-------+
| id | src_id | dst_id | depth |
+----+--------+--------+-------+
| 1 | 1 | 1 | 0 |
| 2 | 2 | 2 | 0 |
| 3 | 1 | 2 | 1 |
| 4 | 3 | 3 | 0 |
| 5 | 1 | 3 | 1 |
| 6 | 4 | 4 | 0 |
| 7 | 1 | 4 | 1 |
| 8 | 5 | 5 | 0 |
| 9 | 2 | 5 | 1 |
| 10 | 1 | 5 | 2 |
| 11 | 6 | 6 | 0 |
| 12 | 2 | 6 | 1 |
| 13 | 1 | 6 | 2 |
| 14 | 7 | 7 | 0 |
| 15 | 3 | 7 | 1 |
| 16 | 1 | 7 | 2 |
| 17 | 8 | 8 | 0 |
| 18 | 3 | 8 | 1 |
| 19 | 1 | 8 | 2 |
| 20 | 9 | 9 | 0 |
| 21 | 4 | 9 | 1 |
| 22 | 1 | 9 | 2 |
+----+--------+--------+-------+
CREATE TABLE locations_relation (
id int IDENTITY(1,1) PRIMARY KEY,
src_id int,
dst_id int,
depth int,
CONSTRAINT FK_src FOREIGN KEY (src_id)
REFERENCES locations (id),
CONSTRAINT FK_dst FOREIGN KEY (dst_id)
REFERENCES locations (id)
)
Now there is a third table, which holds information about documents and is referencing the locations table, which looks like this:
closure_junction
+----+------------+-------------+
| id | country_id | document_id |
+----+------------+-------------+
| 1 | 2 | 1 |
| 2 | 2 | 2 |
| 3 | 6 | 2 |
| 4 | 6 | 3 |
| 5 | 5 | 2 |
| 6 | 5 | 4 |
+----+------------+-------------+
CREATE TABLE closure_junction (
id int IDENTITY(1,1) PRIMARY KEY,
country_id int NOT NULL,
document_id int,
CONSTRAINT FK_countries FOREIGN KEY (id)
REFERENCES countries(id)
)
What I'd like to have is single SQL-Query which counts the document per location and if there are documents in a child it should be counted up in the parent. For example if paris holds 2 documents than france should automatically also hold 2 documents. The query should also output the path of each node to the root aswell as the depth of the node. I know there is way to do this recursively, but I'd like to avoid that.
I have a query which gives me the correct result, but I'm not satisfied with how it works. Is there a way to circumentvent storing the children in a column?
This is my query with the correct output:
;WITH cte (name, path, depth, children) AS
(
SELECT
node.name,
STRING_AGG(locations.name, ' / ' ) WITHIN GROUP (ORDER BY relation.depth DESC) as path,
MAX(relation.depth) as depth,
STRING_AGG(locations.id, ' ') as children
FROM locations node
INNER JOIN locations_relation relation
ON node.id = relation.dst_id
INNER JOIN locations
ON relation.src_id = locations.id
GROUP BY node.name
)
SELECT
name,
path,
depth,
COUNT(DISTINCT document_id) as count_docs
FROM cte
CROSS APPLY string_split(children, ' ')
LEFT JOIN closure_junction ON
closure_junction.country_id = value
GROUP BY name, path, depth
ORDER BY depth ASC
+---------+---------------------------+-------+------------+
| name | path | depth | count_docs |
+---------+---------------------------+-------+------------+
| Europe | Europe | 0 | 0 |
| France | Europe / France | 1 | 2 |
| Germany | Europe / Germany | 1 | 0 |
| Spain | Europe / Spain | 1 | 0 |
| Berlin | Europe / Germany / Berlin | 2 | 0 |
| Madrid | Europe / Spain / Madrid | 2 | 0 |
| Munich | Europe / Germany / Munich | 2 | 0 |
| Nizza | Europe / France / Nizza | 2 | 3 |
| Paris | Europe / France / Paris | 2 | 3 |
+---------+---------------------------+-------+------------+
Would be great if someone could give me a clue on how to accomplish this.
The count you can easily replace with a simple LEFT JOIN, but for this path you will still need to concatenate it somehow.
Something like this:
WITH CTE_path
AS
( SELECT node.id,
STRING_AGG(locations.name, ' / ' ) WITHIN GROUP (ORDER BY relation.depth DESC) as path
FROM locations node
INNER JOIN locations_relation relation
ON node.id = relation.dst_id
INNER JOIN locations
ON relation.src_id = locations.id
GROUP BY node.id)
SELECT l.name,count(DISTINCT cj.document_id),pa.path
FROM locations l
JOIN CTE_path pa
ON pa.id = l.id
LEFT JOIN locations_relation lr
ON l.id = lr.dst_id
LEFT JOIN closure_junction cj
ON cj.country_id = lr.src_id
GROUP BY l.name,pa.path

SQL query to aggregate result from child table

I need to join 4 table and display records in my application
route1
-------------------------
| ID | MODE | SCH DATE |
| 1 | T | 1/12019 |
| 2 | T | 2/12019 |
| 3 | T | 2/12019 |
--------------------------
Stop2
----------------------------
| ID | routeID | LocationID |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 4 |
| 5 | 2 | 5 |
| 6 | 3 | 6 |
-----------------------------
StopOrder2
----------------------------
| ID | StopID | Wight |
| 1 | 1 | 100 |
| 2 | 1 | 2 |
| 3 | 2 | 3 |
| 4 | 2 | 1 |
| 5 | 3 | 2 |
| 6 | 3 | 3 |
| 7 | 4 | 2 |
| 8 | 4 | 3 |
| 9 | 5 | 2 |
| 10 | 5 | 3 |
| 11 | 6 | 2 |
| 12 | 6 | 3 |
-----------------------------
Location
| LocationID | Name, City, Zip
| 1 | name1,city1 1111
| 2 | name2,city2 2222
| 3 | name3,city3 333
-----------------------------
I want final result with each route have how many records and how many orders and sum of all order wight
-----------------------------------------
| RouteID | MODE | SCH DATE |No Of Stop |LastLocatioID|OrderCount|
| 1 | T | 1/12019 | 3 | 3 | 6 |
| 2 | T | 2/12019 | 2 | 5 | 4 |
| 3 | T | 2/12019 | 1 | 6 | 2 |
How can I write the SQL query I need?
All you need is a simple group by:
SELECT
r.ID AS RouteID,
r.MODE,
r.[SCH DATE],
COUNT(s.ID) AS [No Of Stop],
MAX(s.LocationID) AS [LastLocationID],
COUNT(o.ID) AS OrderCount
FROM
#route1 r
INNER JOIN #Stop2 s
ON r.ID = s.routeID
INNER JOIN #StopOrder2 o
ON s.ID = o.StopID
GROUP BY
r.ID,
r.MODE,
r.[SCH DATE]
Output:

How to hide duplicate rows and display 4 count texts in 4 columns

I want to hide duplicate rows based on 2 columns (row,type)
In the status column I have 4 types of text
Enable,Disable,Run,End
Also 4 extra columns for these 4 texts
The number of each text based on that 2 columns is displayed in the corresponding column
I want to convert from :
|--------------------------------|
| id | row |value | type |status |
|--------------------------------|
| 1 | a | a | a |Enable |
| 2 | a | a | a |Disable|
| 3 | a | a | a |Run |
| 4 | a | a | a |End |
| 5 | a | a | a |End |
| |
| 6 | a | a | b |Enable |
| 7 | a | a | b |Run |
| |
| 8 | b | a | b |Enable |
| 9 | b | a | b |Disable|
| |
| 10 | b | a | c |Run |
| 11 | b | a | c |End |
| 12 | b | a | c |End |
| |
| 13 | c | a | a |Enable |
| 14 | c | a | a |Run |
|--------------------------------|
to :
|---------------------------------------------------------------|
| id | row |value | type |status |number |Enable|Disable|Run|End|
|---------------------------------------------------------------|
| 1 | a | a | a |Enable | 5 | 1 | 1 | 1 | 2 |
| 2 | a | a | b |Enable | 2 | 1 | 0 | 1 | 0 |
| 3 | b | a | b |Enable | 2 | 1 | 1 | 0 | 0 |
| 4 | b | a | c |Run | 3 | 0 | 0 | 1 | 2 |
| 5 | c | a | a |Enable | 2 | 1 | 0 | 1 | 0 |
|---------------------------------------------------------------|
my query :
SELECT
ROW_NUMBER() OVER(order by min(id)) AS 'id'
, row
, MIN(value) AS 'value'
, type
, MIN(status) AS 'status'
, COUNT(*) AS'number'
, (SELECT COUNT(1) FROM Work WHERE status LIKE 'Enable' ) AS 'Enable'
, (SELECT COUNT(1) FROM Work WHERE status LIKE 'Disable' ) AS 'Disable'
, (SELECT COUNT(1) FROM Work WHERE status LIKE'Run') AS 'Run'
, (SELECT COUNT(1) FROM Work WHERE status LIKE 'End') AS 'End'
FROM Work AS w
WHERE type ='a'
GROUP BY row,type
ORDER BY MIN(id)
But with this query the output is :
|---------------------------------------------------------------|
| id | row |value | type |status |number |Enable|Disable|Run|End|
|---------------------------------------------------------------|
| 1 | a | a | a |Enable | 5 | 1 | 1 | 1 | 2 |
| 2 | a | a | b |Enable | 2 | 1 | 1 | 1 | 2 |
| 3 | b | a | b |Enable | 2 | 1 | 1 | 1 | 2 |
| 4 | b | a | c |Run | 3 | 1 | 1 | 1 | 2 |
| 5 | c | a | a |Enable | 2 | 1 | 1 | 1 | 2 |
|---------------------------------------------------------------|
There is missing where part in every select count(*)... .
...
,(select count(*) from Work w2 where status like 'Enable' and w.row = w2.row and w.type = w2.type ) as 'Enable'
...

Adding a count column in SQL Server for groups of records

I am trying to update an existing table with an individual count of the record on each row in a count column.
The table has the following columns that need to be incremented:
MBR_NO, CLAIM_N0, Effective_Dt, incr_count
So a sample might look like this before the run:
MBR_NO | CLAIM_N0 | Effective_Dt | incr_count |
-------+----------+----------------+------------+
1 | 2 | 1/1/2015 | NULL |
1 | 4 | 5/5/2015 | NULL |
1 | 5 | 6/7/2016 | NULL |
1 | 7 | 8/7/2016 | NULL |
2 | 2 | 4/3/2015 | NULL |
2 | 5 | 5/21/2015 | NULL |
3 | 8 | 3/27/2015 | NULL |
I want to count by MBR_NO and update the Incr_count to look like this:
MBR_NO | CLAIM_N0 | Effective_Dt | incr_count |
-------+----------+----------------+------------+
1 | 2 | 1/1/2015 | 1 |
1 | 4 | 5/5/2015 | 2 |
1 | 5 | 6/7/2016 | 3 |
1 | 7 | 8/7/2016 | 4 |
2 | 2 | 4/3/2015 | 1 |
2 | 5 | 5/21/2015 | 2 |
3 | 8 | 3/27/2015 | 1 |
I need to change that filed for processing later on.
I know this is not that complex but It seemed that the other topics offered solutions that don't incrementally update. Any help would be appreciated.
You could just do this in a query with
ROW_NUMBER() OVER (PARTITION BY MBR_NO ORDER BY Effective_DT).
but does it matter if the number changes? i.e. in your example if you had
MBR_NO EffectiveDate RowNumber
------------------------------------
2 1/1/2017 1
2 5/1/2017 2
but if you inserted a row with an effective date of say 3/1/2017 it would change the row number for the 5/1/2017 row i.e.
MBR_NO EffectiveDate RowNumber
------------------------------------
2 1/1/2017 1
2 3/1/2017 2
2 5/1/2017 3
You can query as below:
Select MBR_NO, CLAIM_N0, Effective_Dt,
incr_count = count(MBR_NO) over(Partition by MBR_NO order by Effective_Dt)
from yourtable
Output as below:
+--------+----------+--------------+------------+
| MBR_NO | CLAIM_N0 | Effective_Dt | incr_count |
+--------+----------+--------------+------------+
| 1 | 2 | 2015-01-01 | 1 |
| 1 | 4 | 2015-05-05 | 2 |
| 1 | 5 | 2016-06-07 | 3 |
| 1 | 7 | 2016-08-07 | 4 |
| 2 | 2 | 2015-04-03 | 1 |
| 2 | 5 | 2015-05-21 | 2 |
| 3 | 8 | 2015-03-27 | 1 |
+--------+----------+--------------+------------+

Resources