I have three tables and there respective columns
tReferences:
PK_Reference
FK_ReferenceType
ReferenceValue
thePKofMain_FK
tReferencesTypes:
PK_ReferenceType
ReferenceName
tMain:
PK_Main
FirstReferenceValue
SecondReferenceValue
ThirdReferenceValue
Three references have become important enough that they are going to have to go to the tMain table. Let's say the PK of the three references from tReferenceTypes are 321, 654, and 987. I need to copy the references values from tReference to tMain table where each reference has their own columns now, but I have to make sure that I am adding the value from tReference to the correct PK_Main which is suppose to be the same value as the thePKofMain_FK in tReference table, and that I amtReferenceType PK.
I need something like this...
UPDATE tMain
SET
tMain.FirstReferenceValue = (SELECT ReferenceValue FROM tReference WHERE FK_referenceType =321)
FROM tReference
WHERE tReference. thePKofMain_FK = tMain.PK_Main
But I get this messages which makes sense:
Sub query returned more than 1 value. This is not permitted when the
sub query follows =, !=, <, <= , >, >= or when the sub query is used
as an expression. The statement has been terminated.
UPDATE tMain
SET
tMain.FirstReferenceValue = (SELECT ReferenceValue FROM tReference
JOIN tReference on tReference.thePKofMain_FK = tMain.PK_Main
WHERE FK_referenceType =9001649
WHERE FK_referenceType =321)
FROM tReference
WHERE tReference. thePKofMain_FK = tMain.PK_Main
Msg 209, Level 16, State 1, Line 18. Ambiguous column name
'FK_referenceType'. Msg 209, Level 16, State 1, Line 15. Ambiguous
column name 'ReferenceValue'.
OR should I look into doing it in C#?
Some example data:
tReferences:
PK_Reference
123
456
789
FK_ReferenceType:
321
654
987
ReferenceValue
111
a
1
-------------- why I got the first error messages since some reference values are the same
111
c
2
thePKofMain_FK
147
258
369
tReferencesTypes:
PK_ReferenceType
321
654
987
ReferenceName:
FirstReferenceValue
SecondReferenceValue
ThirdReferenceValue
tMain:
PK_Main:
147
258
369
FirstReferenceValue:
Empty
SecondReferenceValue:
Empty
ThirdReferenceValue:
Empty
There is duplicates of ReferenceValues that why the first sql query doesn't work, but even if there are duplicates of the same referenceValue I still need to copy it over to the new table
The second query it accidently typed in WHERE FK_referenceType =9001649 when I was trying to post the question.
Use a Pivot to get the tMain values
INSERT tMain (PK_Main, FirstReferenceValue, SecondReferenceValue, ThirdReferenceValue)
SELECT P.thePKofMain_FK, P.[321], P.[654], P.[987]
FROM (
SELECT FK_ReferenceType, ReferenceValue, thePKofMain_FK
FROM tReference
) T
PIVOT (
MAX(ReferenceValue) FOR FK_ReferenceType IN ([321], [654], [987])
) P
Related
The original query :
with Tr As (
SELECT
DocDtls.Warehouse,
Transactions.Code,
DocDtls.zDate,
Transactions.ID,
Transactions.QtyIn,
Transactions.QtyOut,
Transactions.BalanceAfter
FROM
DocDtls
INNER JOIN Transactions ON DocDtls.[PrimDocNum] = Transactions.[DocNum]
),
formatted_tr as (
select
ID,
Code,
QtyIn,
QtyOut,
BalanceAfter,
LAG(BalanceAfter, 1, 0) Over (
partition by Warehouse,
Code
order by
Code,zDate,ID
) Prev_BlncAfter
from
Tr
)
select ID,Code,QtyIn,QtyOut,BalanceAfter
,SUM(Prev_BlncAfter + QtyIn)-QtyOut As NewBlncAfter
from formatted_tr
group by ID,Code,QtyIn,QtyOut,BalanceAfter;
;
Explaining the idea :
Let's say that the query returns all transactions of Item X and there are 10 rows as result , I need to loop through all 10 rows and SET BalanceAfter( for the first transaction QtyIn-QtyOut , Any other transaction (PreviousBalanceAfter+QtyIn)-QtyOut) And so on .
What I've tried :
I tried to put the query result in a Datatable then filter it one more time using DataView to get the NewBlncAfter of the DataGridView current row ID only so the Dataview only have one row and save it in a variable - Working well so far - when I try to loop through all rows in my DataGridview and update BalanceAfter I got :
Must Declare Scalar Variable #Newblnc
You can find the whole code in here :
My Code
So Is there a direct way to update all transactions BalanceAfter to equal
EDIT #1 : I used #Charliface query and the result was :
I used the old query to compare the results , The BalanceAfter should equal NewBlncAfter in every row .
Edit #2 : Using SUM instead of LAG causing wrong calculation and if I used the query more than once the result in BalanceAfter is multiplied
ID Code QtyIn QtyOut BalanceAfter
9 100001 20000 0 20000
14 100001 0 6000 40000
21 100001 3500 0 60000
24 100001 0 3000 80000
The main idea and the desired result for example :
ID Code QtyIn QtyOut BalanceAfter
9 100001 20000 0 20000
14 100001 0 6000 14000
21 100001 3500 0 17500
24 100001 0 3000 14500
The formula is :
for the first transaction QtyIn-QtyOut , Any other transaction (PreviousBalanceAfter+QtyIn)-QtyOut And so on .
Firstly, I see no reason at all to pull all this data into C# only to then update row-by-row (which is highly inefficient). You can do this in a single batch update.
It's not quite clear what result you want, but it seems you want to just assign a running SUM calculation, rather than LAG.
Furthermore:
The second CTE is unnecessary and can be collapsed into the first.
Partitioning and ordering by the same column in an OVER makes no sense.
The final GROUP BY also makes no sense and appears unnecessary, as you are grouping by a primary key.
WITH Tr AS (
SELECT
d.Warehouse,
t.Code,
d.zDate,
t.ID,
t.QtyIn,
t.QtyOut,
t.BalanceAfter,
SUM(t.QtyIn - t.QtyOut) OVER (
PARTITION BY d.Warehouse, t.Code
ORDER BY d.zDate, t.ID
ROWS UNBOUNDED PRECEDING
) BlncAfter
FROM
DocDtls d
INNER JOIN Transactions t ON d.PrimDocNum = t.DocNum
WHERE t.Code = #VariableCode
)
UPDATE Tr
SET BalanceAfter = BlncAfter;
One final point: why bother storing this information in a new column at all? Why not just calculate it when you need to, using SUM OVER?
I have this nitpicked columns on my table (cause the rest are irrelevant in the problem).
ID | Generic Name
-----+---------------
001 | Cetirizine
002 | Cetirizine
003 |
004 | Paracetamol
I want my combo box to display only a single entry Cetirizine (or any data that has been duplicated) and no empty generic names (some data have no generic names).
I've tried:
select
Item_GenName
from
ItemMasterlistTable
where
nullif(convert(varchar, Item_GenName), '') is not null
but it only achieves the no empty data part.
I've tried using DISTINCT, but it doesn't work and somebody suggested JOIN but I don't think it works since I'm only using 1 table.
I've also tried:
SELECT
MIN(Item_ID) AS Item_ID, Item_GenName
FROM
ItemMasterlistTable
GROUP BY
Item_GenName
but there's always an error:
The text, ntext, and image data types cannot be compared or sorted, except when using IS NULL or LIKE operator.
The following query should return only distinct, non-empty Item_GenNames:
SELECT DISTINCT Item_GenName
FROM ItemMasterlistTable
// because Item_GenName is of type *text*, the below in lieu of `is not null` and `!= ''`
WHERE datalength(Item_GenName) != 0
You said you tried DISTINCT and it did not work so I want to clarify,
The DISTINCT keyword will return unique records over the complete domain of your select statement. If you include the ID column in your select statement, even a distinct selection will return your duplicate Item_GenNames b/c the combined ID / Item_GenName record would be unique. Include only Item_GenName in your select clause to guarantee distinct values for this column.
The following query might be useful.
declare #tab table (ID varchar(10), Generic_Name varchar(100))
insert into #tab
select '001', 'Cetirizine'
union
select '002', 'Cetirizine'
union
select '003', ''
union
select '004', 'Paracetamol'
select MIN(substring(ID, 1, 10)) ID, substring(Generic_Name, 1, 1000) Generic_Name
from #tab
where substring(Generic_Name, 1, 1) <> ''
group by substring(Generic_Name, 1, 1000)
You can try this query
Select distinct Item_GenName FROM(
Select * FROM ItemMasterlistTable where Item_GenName <> ''
)t
Inner query remove non-empty records and outer query get the distinct record from the inner output
I want to add to a table in my DB ("InjuryScenario") a dynamic id (because i work with visual studio c#) and i tried this:
declare #InjuryScenarioTMPp int;
set #InjuryScenarioTMPp = (select MAX (InjuryScenario_id) from InjuryScenario) +1;
print #InjuryScenarioTMPp;
when i printed it, it doesn't show me anything.
when i tried to add a row to the table and i tried the 3 rows (up) again it does print "2".
maybe when i don't have any rows in the table it doesn't know how to do (NULL+1)?
does anyone have an idea why?
It depends on what kind of database would you like to use. For example, in MySQL you have to use AUTO INCREMENT on one field. But in Postgres or in Oracle, you should create first a sequence and later than add the next value of this sequence to new record.
A NULLvalue is an unknown value, and the result of arithmetic on unknown values is also unknown. What you can do is to use either theCOALESCEor theISNULLfunction to replace the NULLvalue with 0when you use it:
declare #InjuryScenarioTMPp int;
set #InjuryScenarioTMPp = (select ISNULL(MAX(InjuryScenario_id),0) from InjuryScenario) + 1;
print #InjuryScenarioTMPp;
See MSDN: COALESCE and ISNULL
For an example:
declare #i int
set #i = null
select #i+1, coalesce(#i, 0)+1, isnull(#i, 0)+1
set #i = 1
select #i+1, coalesce(#i, 0)+1, isnull(#i, 0)+1
Output:
----------- ----------- -----------
NULL 1 1
(1 row(s) affected)
----------- ----------- -----------
2 2 2
(1 row(s) affected)
I have a stored procedure :
CREATE PROCEDURE SELECT_Some_Data
#Sreachstr nvarchar(200)
AS
BEGIN
SELECT ROW_NUMBER() OVER(ORDER BY [Document].DocNo DESC) AS Row,*
FROM Document WHERE DocNo=#Sreachstr
END
when I execute it with #Sreachstr='153', it returns 15 records.
I use Entity Framework to get the data returned by the stored procedure:
public static List<DocumentInfo_Full_Data> SelectByDocNo(string SearchStr)
{
using (LibEntities_new db = new LibEntities_new())
{
return SelectByDocNo(db, SearchStr);
}
}
private static List<DocumentInfo_Full_Data> SelectByDocNo(LibEntities_new db, String SearchStr)
{
return db.SelectByDocNo(SearchStr).ToList();
}
public ObjectResult<DocumentInfo_Full_Data> SelectByDocNo(global::System.String searchStr)
{
ObjectParameter searchStrParameter;
if (searchStr != null)
{
searchStrParameter = new ObjectParameter("SearchStr", searchStr);
}
else
{
searchStrParameter = new ObjectParameter("SearchStr", typeof(global::System.String));
}
return base.ExecuteFunction<DocumentInfo_Full_Data>("SelectByDocNo", searchStrParameter);
}
When I call this method with parameter SearchStr="15" , I see one record that 15 times is repeated instead of 15 different records.
I had this happen to me once when I was selecting rows from a view in EF.
Since the view itself doesn't have a primary key, EF wasn't able to determine the key - instead, EF created a "guessed" key based on all non-nullable columns from the view.
My view returned four rows of data, e.g.
Col1 Col2 Col3 Col4
1 2 'ABC' 42
1 2 'DEF' 57
1 2 'GHI' 4711
1 2 'JKL' 404
--> my query worked just fine in SQL Server Management Studio.
The "key" that EF had guessed was based on (Col1, Col2).
Now when I retrieved the rows using EF, this happen:
the first row got selected - EF saw it didn't have any data yet, so it stored that row in its result set
the next row was selected - EF determined that the key was the same ( (1,2) again) so it assumed this was the same row again; same key -> same row, so that same entity got stored a second, third and fourth time
So in the end, what I got back from EF was
Col1 Col2 Col3 Col4
1 2 'ABC' 42
1 2 'ABC' 42
1 2 'ABC' 42
1 2 'ABC' 42
because the key that determines uniqueness of an entity in EF was the same for each of the four columns from the database.
So this might be happening in your case, too - especially if your created a new complex type for your data returned from the stored procedure - and if your key on the EF entity (DocumentInfo_Full_Data) is not properly set to an actual, really identifying column (or set of columns) from the database. Check it out!
I have what would seem to be a simple problem but the solutions I have tried to date have left me wanting in the execution areas. Speeds seem fine on small (<10000) data sets but quickly take more and more time as the counts go up.
In SQL Server 2008 R2 I have a table with four columns in it: Id, ParentId, ControlNum, ParentControlNum.
The Id and ParentId information is filled in. An Id always has a value, the ParentId is null if the row has no parent, otherwise its the the value of an Id within the table that represents the parent row.
The issue is that the Id and ParentIds are all over the place. All of the Ids are added to the table then they are processed to add the children. This is a set part of the problem and is not something that can be changed.
What I need to be able to do is to generate the ControlNum values in order obeying the Parent Child relationship. My current logic uses a bit of C# and SQL SELECT/UPDATE commands to accomplish this, but as mentioned performance is a great concern.
In Pseudo-Code
Select all Id's where the parent Id is null (All root entries)
Foreach (Id)
GenerateControlNum(Id, CurrentCounterValue, CurrentCounterValue)
GenerateControlNum(Id, CurrentCounterValue, ParentCounterValue)
Set Id's ControlNum to CurrentCounterValue
Set Id's ParentControlNum to CurrentCounterValue
Increment CurrentCounterValue
Select All Id's where ParentId == Id (All my direct children)
Foreach (ChildId)
GenerateControlNum(ChildId, CurrentCounterValue, Id's ControlNum);
Baseline is trying to make this execute faster, idealy completely in SQL would be preffered. I am trying along the lines of a CTE populated with the RootIds and then going through them with a MERGE statement but I can just not seem to get the counter value to work properly for setting the ControlNum values.
Is this even possible in SQL or is this too much of a procedural type of processing?
Example Table Data from how it currently runs: BEFORE
ID ParentId ControlNum ParentControlNum
8C821027-A6F9-E011-AB48-B499BAE13A62 756F981E-A6F9-E011-AB48-B499BAE13A62 0 NULL
D7DB6033-A6F9-E011-AB48-B499BAE13A62 756F981E-A6F9-E011-AB48-B499BAE13A62 0 NULL
D2E36033-A6F9-E011-AB48-B499BAE13A62 C9E36033-A6F9-E011-AB48-B499BAE13A62 0 NULL
8FE66033-A6F9-E011-AB48-B499BAE13A62 58E66033-A6F9-E011-AB48-B499BAE13A62 0 NULL
37EC6033-A6F9-E011-AB48-B499BAE13A62 2FEC6033-A6F9-E011-AB48-B499BAE13A62 0 NULL
41EC6033-A6F9-E011-AB48-B499BAE13A62 2FEC6033-A6F9-E011-AB48-B499BAE13A62 0 NULL
DDED6033-A6F9-E011-AB48-B499BAE13A62 BCED6033-A6F9-E011-AB48-B499BAE13A62 0 NULL
DC69981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
166A981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
4D6A981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
856A981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
F56A981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
2E6B981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
666B981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
9D6B981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 NULL
AFTER
ID ParentId ControlNum ParentControlNum
8C821027-A6F9-E011-AB48-B499BAE13A62 756F981E-A6F9-E011-AB48-B499BAE13A62 22 21
D7DB6033-A6F9-E011-AB48-B499BAE13A62 756F981E-A6F9-E011-AB48-B499BAE13A62 24 21
D2E36033-A6F9-E011-AB48-B499BAE13A62 C9E36033-A6F9-E011-AB48-B499BAE13A62 58 57
8FE66033-A6F9-E011-AB48-B499BAE13A62 58E66033-A6F9-E011-AB48-B499BAE13A62 69 68
37EC6033-A6F9-E011-AB48-B499BAE13A62 2FEC6033-A6F9-E011-AB48-B499BAE13A62 86 85
41EC6033-A6F9-E011-AB48-B499BAE13A62 2FEC6033-A6F9-E011-AB48-B499BAE13A62 88 85
DDED6033-A6F9-E011-AB48-B499BAE13A62 BCED6033-A6F9-E011-AB48-B499BAE13A62 95 94
DC69981E-A6F9-E011-AB48-B499BAE13A62 NULL 0 0
166A981E-A6F9-E011-AB48-B499BAE13A62 NULL 1 1
4D6A981E-A6F9-E011-AB48-B499BAE13A62 NULL 2 2
856A981E-A6F9-E011-AB48-B499BAE13A62 NULL 3 3
F56A981E-A6F9-E011-AB48-B499BAE13A62 NULL 4 4
2E6B981E-A6F9-E011-AB48-B499BAE13A62 NULL 5 5
666B981E-A6F9-E011-AB48-B499BAE13A62 NULL 6 6
9D6B981E-A6F9-E011-AB48-B499BAE13A62 NULL 7 7
The data set I have is 104 entries right now so this is just the first 15. The objects with out parents are at the bottom, those are examples of root entries and have their control number and parent control number set to the same value. At the top of the table we see a few objects that have the same parents and so have matching parent control numbers and fairly close control numbers themselves (there must be row between ControlNum 22 and 24 also from parent 21 for example. same for the 86 to 88 jump, they are just not in the table next to each other).
Hope this makes it more clear.
EDIT: More clarity based on the answer given by Mikael
Below are ControlNum values displayed in the hierarchy based on their Id and ParentId information. Normally these would be listed 1, 2, 3 ... 8 but its easier not to clutter up the display with (child of) messages all over.
1
4
7
8
5
2
6
3
What I need is
1
2
3
4
5
6
7
8
This is why recursion has been the way that I have been going is I need to assign a ControlNum to the root object, and then the next object needs to be its first child followed by that objects children and so on before going on to the next root object.
I guess what I am saying is this is a breadth first and what I am in need of is a depth first.
Not sure I get all of your requirement but here is a start. Tell me if it does what you want or if the numbers are not generated correctly.
;with C as
(
select ID,
ParentID,
ControlNum,
ParentControlNum,
row_number() over(order by ParentID, ID) - 1 as rn
from YourTable
)
update C1
set ControlNum = C1.rn,
ParentControlNum = case when C1.ParentID is null
then C1.rn
else C2.rn
end
from C as C1
left outer join C as C2
on C1.ParentID = C2.ID
Run it on SE-Data with slightly modified input: https://data.stackexchange.com/stackoverflow/q/115625/
Version 2
First a recursive CTE R,that builds a string to be used as order by when generating values for ControlNum. After that it is pretty much the same as above.
;with R as
(
select ID,
ParentID,
cast(ID as varchar(max)) as Sort
from YourTable
where ParentID is null
union all
select T.ID,
T.ParentID,
R.Sort+cast(T.ID as varchar(max))
from YourTable as T
inner join R
on R.ID = T.ParentID
),
C as
(
select ID,
ParentID,
row_number() over(order by Sort) - 1 as rn
from R
)
update T
set ControlNum = C1.rn,
ParentControlNum = case when C1.ParentID is null
then C1.rn
else C2.rn
end
from YourTable as T
inner join C as C1
on T.ID = C1.ID
left outer join C as C2
on T.ParentID = C2.ID
Test here: https://data.stackexchange.com/stackoverflow/q/115626/
Note: I guess this is a one time thing you will do with some data because you will have a hard time adding new nodes and at the same time uphold the numbering like this. If you for instance add a new child node to the first node you will have to assign all ControlNum += 1 for all nodes "below" and reassign all ParentControlNum.