TSQL -- Retrieve parent ID - sql

The raw data in my table consists of an ID column and a column 'IsFolder' which can be 1 or 0, like this:
ID IsFolder
1 1
2 0
3 0
4 1
5 0
6 0
7 0
8 0
9 0
10 0
11 1
12 0
13 0
14 0
15 1
16 0
17 0
The way the code interprets this is that if a line has a 1 for 'IsFolder' then it is a Folder, and all of the tasks below it (until you hit the next Folder) are children of that folder.
What I'd like to have is a Select statement that will just return the ID of the parent folder for all non-folder tasks. So something like:
ID ParentFolder
2 1
3 1
5 4
6 4
7 4
8 4
9 4
10 4
12 11
13 11
14 11
16 15
17 15
I'm using MS SQL Server Management Studio 2005. I feel like this is an easy answer to those familiar with using cursors (which I am not). I can't think of any other way to do it but maybe someone else can. Anyway thanks in advance for any answers and sorry if I did something wrong, this is my first post.

You don't need a cursor for that - just a subquery:
SELECT ID,
(SELECT MAX(ID)
FROM Folders
WHERE ID < f.ID
AND IsFolder = 1) AS Parent
FROM Folders f
WHERE IsFolder = 0

I'd just like to point out that this task would be much easier, and the overall design much more extensible, if the structure of the data was changed a little. How are you going to add a task to folder 4, for example? If the parent and child relationship was extracted to two different tables, it might help.

Related

Rearranging SQL Query Results

I am working on an application that queries a SQL database to get Billing of Material information. I have successfully queried out the data that I wanted using the following query.
WITH bom (bomItem, partId, btmlvl)
AS
(
SELECT [bomItem], [partId], [btmlvl]
FROM [TESTDB].[dbo].[BOMTABLE]
WHERE [TESTDB].[dbo].[BOMTABLE].[bomItem] = 'PART# GOES HERE, PASSED IN BY THE APP'
UNION ALL
SELECT subQuery.bomItem, subQuery.partId, subQuery.btmlvl
FROM [TESTDB].[dbo].[BOMTABLE] AS subQuery
INNER JOIN bom AS mainQuery
on subQuery.bomItem = mainQuery.partId
)
SELECT [bomItem], [partId], [btmlvl]
FROM bom
The query results in (Sample Data):
bomItem partId btmlvl
---------------------------------
1 2 1
1 3 1
1 4 0
1 5 1
1 6 1
1 7 1
1 8 0
1 9 1
1 10 1
1 11 1
8 12 1
8 10 1
8 11 1
8 13 1
8 14 1
8 15 1
8 16 1
4 17 1
4 18 1
4 19 1
The data works as follows:
bomItem - The part number of the assembly that I am looking up the bill of materials for
partId - All of the parts and sub-assemblies tied to the bomItem I'm looking up
btmlvl - 0 indicates it's a sub-assembly, 1 indicates a standalone part (not really important, I was just using this to make sure I was getting the results that I wanted)
And what I want it to look like is (Expected Results):
bomItem partId btmlvl
---------------------------------
1 2 1
1 3 1
1 4 0
4 17 1
4 18 1
4 19 1
1 5 1
1 6 1
1 7 1
1 8 0
8 12 1
8 10 1
8 11 1
8 13 1
8 14 1
8 15 1
8 16 1
1 9 1
1 10 1
1 11 1
I could export it to a CSV or something else and write a script to rearrange the data, but I would prefer if it could be done as part of the SQL query. I messed around some with CASE statements but didn't quite achieve the desired results.
Bonus points if it could be aligned as follows (again the btmlvl isn't important, and will ultimately be removed). Again, novice SQL user here, but I think this would be possible using a PIVOT? (I just haven't gotten that far):
bomItem partId partId2
---------------------------------
...
1 8
8 12
8 10
8 11
8 13
8 14
8 15
8 16
...
Any help would be greatly appreciated, and please excuse the lengthiness of this post!
EDIT:
The only difference between my actual data and what I supplied is I simplified the part numbers from 11 characters strings to one-digit and two-digit integers and also removed other information I thought was irrelevant (e.g. qty on hand, purchasing cost, etc.). The first set of data is the sample data resulting from passing in "1" to WHERE [TESTDB].[dbo].[BOMTABLE].[bomItem] = 'PART# GOES HERE, PASSED IN BY THE APP'. This means that the first 10 lines of that data (again, anything with the bomItem == "1"), are all of the parts that make up bomItem == "1".
Looking at the "btmlvl" column for all bomItem == "1", you can see partId's 4 & 8 are assemblies (read sub-assemblies of bomItem == "1"), because btmlvl == "0". This means I need to perform additional queries to obtain the bill of materials for those part numbers. This is where the subQuery within the CTE comes in, giving me the line items starting with bomItem == "4" and bomItem == "8".
The difference between the output as it stands right now, and the output that is desired is the current output lists all parts for bomItem == "1", then all parts for bomItem == "8", and lastly all parts for bomItem == "4".
But what I want is where bomItem == "1" & partId's 1 through 3 to appear as they are right now, but once partId == "4", directly underneath that line I want all of the lines where bomItem == "4", then continue with the lines that contain bomItem == "1" & partId's 5, 6, 7, but again once partId 8 is reached, do a similar thing as with partId 4, then finish partId's 9, 10, 11 as normal.
This is inherently hierarchal data, so you need a self-join.
I think this gets you what you want.
SELECT a.* FROM bom a
LEFT JOIN bom b
ON a.bomitem = b.partID
ORDER BY ISNULL (b.partID, a.partID), a.partID

SQL table structure for store value against list of combination

I have a requirement from client where I need to store a value against list of combination.
For example I have following LOBs and against each combination I need to store a value.
Auto
WC
Personal
I purposed multiple solutions he is not satisfied with anyone.
Solution 1: create single table, insert value against all possible combination(string) something like
LOB Value
Auto 1
WC 2
Personal 3
Auto,WC 4
Auto, personal 5
WC, Personal 6
Auto, WC, Personal 7
Solution 2: create lkp_lob, lob_group and lob_group_detail tables. Each group combination represent a group.
Lkp_lob
Lob_key Name
1 Auto
2 WC
3 Person
Lob_group (unique query constrain on lob_group_key and lob_key)
Lob_group_key Lob_key
1 1
2 2
3 3
4 1
4 2
5 1
5 3
6 2
6 3
7 1
7 2
7 3
Lob_group_detail
Lob_group_key Value
1 1
2 2
3 3
4 4
5 5
6 6
7 7
Any suggestion would be highly appreciated.
First of all I did not understood that terms you said.
But from database perspective it is always good to have multiple tables for each module. You will be facing less difficulties when doing CRUD. And will be more faster.

Double Join to get data from a table based on other two tables

I have three tables with the following key fields:
CONTRACTS
reference
package
EVENTS
reference
condition1
condition2
TRADES
reference
event_reference
Basically, what I would like to do is the following:
Get all the reference of the table EVENTS where the two conditions (condition1 and condition2) are met;
Hence, getting all the reference of the table TRADES where TRADES.event_reference = EVENTS.reference
Finally, getting the CONTRACTS.package where the CONTRACTS.reference = TRADES.reference (after having filtered the data at the point 2).
In order to do this, I have tried a JOIN statement:
SELECT CONTRACTS.package
FROM CONTRACTS
JOIN TRADES ON CONTRACTS.reference = TRADES.reference
JOIN EVENTS ON TRADES.event_reference = EVENTS.reference
WHERE EVENTS.condition1 = '1.511' AND EVENTS.condition2 IN (1,2)
However, the above (which is executed without errors) does not issue any result, and I would actually expect to see some.
I hence understand that I'm being wrong in the logic that I follow: could anyone please help?
EDIT: this is an example of how the data look like (in yellow, I have highlighted the data that would be touched in the query if it was working as I had it in mind:
...here is the expected result:
1 (package of 4, related to 11 which satisfies condition 1 and 2)
2 (package of 6, related to 13 which satisfies condition 1 and 2)
4 (package of 10, related to 16 which satisfies condition 1 and 2)
and here are the data to copy-paste them:
CONTRACTS
reference package
1 1
2 1
3 1
4 1
5 2
6 2
7 3
8 3
9 4
10 4
EVENTS
reference condition1 condition2
10 1.511 0
11 1.511 1
12 1.202 0
13 1.511 2
14 1.511 0
15 1.202 0
16 1.511 1
TRADES
reference event_reference
2 10
4 11
5 12
6 13
7 14
9 15
10 16
Your query looks OK
SQL Fiddle Demo
SELECT CONTRACTS.package
FROM CONTRACTS
JOIN TRADES ON CONTRACTS.reference = TRADES.reference
JOIN EVENTS ON TRADES.event_reference = EVENTS.reference
WHERE EVENTS.condition1 = 'true' AND EVENTS.condition2 = 'true'
OUTPUT
| package |
|---------|
| 1 |
| 2 |
| 4 |

MDX: iif condition on the value of dimension

I have 1 Virtual cube consists of 2 cubes.
Example of fact table of 1st cube.
id object_id time_id date_id state
1 10 2 1 0
2 11 5 1 0
3 10 7 1 1
4 10 3 1 0
5 11 4 1 0
6 11 7 1 1
7 10 8 1 0
8 11 5 1 0
9 10 7 1 1
10 10 9 1 2
Where State: 0 - Ok, 1 - Down, 2 - Unknown
For this cube I have one measure StateCount it should count States for each object_id.
Here for example we have such result:
for 10 : 3 times Ok , 2 times Down, 1 time Unknown
for 11 : 3 times Ok , 1 time Down
Second cube looks like this:
id object_id time_id date_id status
1 10 2 1 0
2 11 5 1 0
3 10 7 1 1
4 10 3 1 1
5 11 4 1 1
Where Status: 0 - out, 1 - in. I keep this in StatusDim.
In this table I keep records that should not be count. If object have status 1 that means that I have exclude it from count.
If we intersect these tables and use StateCount we will receive this result:
for 10 : 2 times Ok , 1 times Down, 1 time Unknown
for 11 : 2 times Ok , 1 time Down
As far as i know, i must use calculated member with IIF condition. Currently I'm trying something like this.
WITH MEMBER [Measures].[StateTimeCountDown] AS(
iif(
[StatusDimDown.DowntimeHierarchy].[DowntimeStatus].CurrentMember.MemberValue
<> "in"
, [Measures].[StateTimeCount]
, null )
)
The multidimensional way to do this would be to make attributes from your state and status columns (hopefully with user understandable members, i. e. using "Ok" and not "0"). Then, you can just use a normal count measure on the fact tables, and slice by these attributes. No need for complex calculation definitions.

Sql Server Row Concatenation

I have a table (table variable in-fact) that holds several thousand (50k approx) rows of the form:
group (int) isok (bit) x y
20 0 1 1
20 1 2 1
20 1 3 1
20 0 1 2
20 0 2 1
21 1 1 1
21 0 2 1
21 1 3 1
21 0 1 2
21 1 2 2
And to pull this back to the client is a fairly hefty task (especially since isok is a bit). What I would like to do is transform this into the form:
group mask
20 01100
21 10101
And maybe go even a step further by encoding this into a long etc.
NOTE: The way in which the data is stored currently cannot be changed.
Is something like this possible in SQL Server 2005, and if possible even 2000 (quite important)?
EDIT: I forgot to make it clear that the original table is already in an implicit ordering that needs to be maintained, there isnt one column that acts as a linear sequence, but rather the ordering is based on two other columns (integers) as above (x & y)
You can treat the bit as a string ('0', '1') and deploy one of the many string aggregate concatenation methods described here: http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/