I have a SQL statement that imports my product inventory from a Access.MDB file. The select statement is below. (well a portion of it)
SELECT
Brand, DESCRIPTION AS Model,
SECONDDESCRIPTION AS Description,
PRODUCT AS [Product Code], TYPE AS Batch, INACTIVE,
CORE AS [Core Range],
IIF([CUSTORD] IS NULL, ROUND(ON_HAND), (IIF(TYPE = 'DISP',ROUND(ON_HAND),ROUND(ON_HAND)-CUSTORD))) AS SOH
You may notice that the select statement will minus any items that are on a customer order from the SOH values. for clarity below is the line that does just that.
IIF([CUSTORD] IS NULL, ROUND(ON_HAND), (IIF(TYPE = 'DISP',ROUND(ON_HAND),ROUND(ON_HAND)-CUSTORD))) AS SOH
The problem i have is, that 1 product code, can have multiple batches, and if an item only has a qty of 1 in each batch, and then the customer order column also contains a 1, this results in 1 - 1 = 0.
However the customer orders column is really indicating that only 1 of the product codes in on a customer order, not that specific batch.
Is there a way to check if that product code has already been "Selected" and has a Customer Order Qty against it and if it does then ignore the customer order qty against this next batch in the table?
To help explain it a little here is a rough idea of the table that would be imported.
Product
Batch_Number
ON_HAND
CUSTORD
Apples
123456
5
1
Apples
234567
1
1
Apples
587554
1
1
Bananas
1548777
1
0
so in the table above with my existing select statement, my results would be
Apples 4 in batch 123456
Bananas 1 in batch 1548777
As the next two lines of apples would actually end up with a value of 0 in batches 234567 and 587554
my program is set to then only return to the user values of items they can sell with a SOH qty > 0
so i need the final datatable in my program to look like this:
Product
Batch_Number
ON_HAND
CUSTORD
Apples
123456
5
1
Apples
234567
1
0
Apples
587554
1
0
Bananas
1548777
1
0
In my table Batch Number is the unique identifier and does not occur twice in the table.
Im working in VB.NET so if it could not be done in the SQL select statement i could be open to the idea of adjusting the values in the dataset datatable, however that would probably be made harder by the fact that the SQL Select statement i'm using never actually imports the CUSTORD column of data into my datatable. As i was trying to handle the SOH values directly at the select statement level.
Hope i have not confused anyone, and explained it as simple as possible.
I have no idea what your initial code has to do with the question. But let me assume that you have a table in the format shown in the question and you want to set on_hand to 0 for all but the first row for each product. You can use:
select product, batch_number, custord,
iif( t.batch_number = (select top 1 t2.batch_number
from t as t2
where t2.product = t.product
order by t2.on_hand desc, t2.batch_number
),
t.on_hand, 0
) as adjusted_on_hand
from t
order by product, on_hand desc, batch_number
I have three SQL tables as below, the first one named 'repairparts':
repairparts
-----------------------------------
ID Part Quantity
1 AAA1000 1
2 AAB1000 1
3 AAC1000 1
And the second named 'partslist':
partslist
------------------------------------
Part Price
AAA1000 1.50
AAB1000 3.00
AAC1000 2.00
Now with only being given the ID value of '1', I want to be able to take the part number, and quantity from the first table named 'repairparts' linked to that ID, and combine that with the price of the same part number in the second table named 'partslist', and insert those four piece of data in to the third table named 'estimateparts'.
So the outcome would be this being inserted into the table named 'estimateparts':
estimateparts
-----------------------------------
ID Part Quantity Price
1 AAA1000 1 1.50
I've read that I should use the UNION function and have tried the following, but it does nothing:
INSERT INTO estimateparts (ID, Part, Quantity, Price)
SELECT ID, Part, Quantity FROM repairparts WHERE ID='1'
UNION SELECT Price FROM partslist WHERE Part=repairparts.Part
Really appreciate any advice that can be given.
Thank you.
It sounds like you want a simple join, if I'm not missing something:
select rp.id, rp.part, rp.quantity, pl.price
from repairparts rp join
partslist pl
on rp.part = pl.part
where rp.id = 1;
I have a query similar to the following:
SELECT CASE WHEN (GROUPING(Name) = 1) THEN 'All' ELSE Name END AS Name,
CASE WHEN (GROUPING(Type) = 1) THEN 'All' ELSE Type END AS Type,
sum(quantity) AS [Quantity],
CAST(sum(quantity) * (SELECT QuantityMultiplier FROM QuantityMultipliers WHERE a = t.b) AS DECIMAL(18,2)) AS Multiplied Quantity
FROM #Table t
GROUP BY Name, Type WITH ROLLUP
I'm trying to return a list of Names, Types, a summed Quantity and a summed quantity multiplied by an arbitrary number. All fine so far. I also need to return a sub-total row per Name and per Type, such as the following
Name Type Quantity Multiplied Quantity
------- --------- ----------- -------------------
a 1 2 4
a 2 3 3
a ALL 5 7
b 1 6 12
b 2 1 1
b ALL 7 13
ALL ALL 24 40
The first 3 columns are fine. I'm getting null values in the rollup rows for the multiplied quantity though. The only reason I can think this is happening is because SQL doesn't recognize the last column as an aggregate now that I've multiplied it by something.
Can I somehow work around this without things getting too convoluted?
I will be falling back onto temporary tables if this can't be done.
In your sub-query to acquire the multiplier, you have WHERE a=b. Are either a or b from the tables in your main query?
If these values are static (nothing to do with the main query), it looks like it should be fine...
If the a or b values are the name or type field, they can be NULL for the rollup records. If so, you can change to something similiar to...
CAST(sum(quantity * (<multiplie_query>)) AS DECIMAL(18,2)).
If a or b are other field from your main query, you'd be getting multiple records back, not just a single multiplier. You could change to something like...
CAST(sum(quantity) * (SELECT MAX(multiplier) FROM ...)) AS DECIMAL(18,2))
I have a table for a menu system with the following structure, and some data.
ID, Text, ParentID, DestinationID
1, Applications, (null), (null)
2, Games, (null), (null)
3, Office, 1, (null)
4, Text Editing, 1, (null)
5, Media, (null), (null)
6, Word, 3, 1
7, Excel, 3, 2
8, Crysis, 2, 3
What I need is a query to which I can pass the menu ID, and it will return a list of items that have that ID as a child. BUT, I need it to only return children that have a valid path to a destination. So in the example above, the user will be presented initially with (Applications, Games), when he selects Applicaions, he is presented with (Office). Text Editing and Media should be omitted, because there are no valid destinations beneath them.
The trickiest thing about this, is that there is no predetermined depth to any given menu.
EDIT:
Today, the problem came up for MS SQL 2008, but in the past 2 weeks I've needed similar solutions for SQLite and SQL CE. The ideal solution should not be tied to any specific SQL engine.
SQL server only, but it sounds like a job for Common Table Expressions.
In Oracle:
SELECT m.*, level
FROM my_table m
START WITH
Id = :startID
CONNECT BY
ParentID = PRIOR Id
AND DestinationID IS NOT NULL
There is no way to do it in ANSI SQL with a single query. You may create an additional column AccessPath for you table:
ID, Text, ParentID, DestinationID AccessPath
1, Applications, (null), (null), "1"
2, Games, (null), (null), "2"
3, Office, 1, (null), "1.3"
4, Text Editing, 1, (null), "1.4"
5, Media, (null), (null), "5"
6, Word, 3, 1, "1.3.6"
7, Excel, 3, 2, "1.3.7"
8, Crysis, 2, 3, "1.2.8"
, and query:
SELECT mp.Id, mp.Text
FROM my_table mp, my_table mc
WHERE mp.parentID = #startingParent
AND mc.Id <> mp.Id
AND SUBSTR(mc.AccessPath, LENGTH(mp.AccessPath)) = mp.AccessPath
GROUP BY
mp.Id, mp.Text
It's a bad idea to start with NULL, as the index on ParentID cannot be used in this case. For a start, use a fake parentID of 0 instead of NULL.
If the hierarchy/tree that you are stroing in your database does not change very often, I would recommend to use the modified preorder tree traversal (MPTT) algorithm. That would require a different table schema, but would allow you to request a whole subtree with a simple SQL statement (no recursion, etc.).
The article on Storing Hierarchical Data in a Database describes this method in detail.
In your example you would get the following tree, where I call the red numbers the left value and the green right value of a node.
Now, if you want to select the Office subtree, you can do this with:
SELECT * FROM tree WHERE left BETWEEN 10 AND 15 AND destination IS NOT NULL
If your DB does not support the BETWEEN statement, you can of course write left > 10 AND left < 15 instead.
Your table would look like this:
name | left | right | destination
------------------------------------------
root | 1 | 17 | NULL
Applications | 7 | 16 | ...
...
If this is a problem that interests you (or plagues you), you may want to check out: Joe Celko's Trees and Hierarchies in SQL for Smarties.
As others have pointed out, there's no way in standard ANSI SQL to do what you want. For something like this, I once implemented on SQL 2000 a system for tracking components of products an ex employer made - each "product" could be atomic component like, say, screw A500. This component could be used in "composite" components: some A500 screws plus 6 B120 wood boards conformed a C90 "stylish tool box". That box, plus more screws and a motor "M500" could conform a carpetry tool.
I designed a table "Product" like this:
ID, PartName, Description
1, A500, "Screw A500"
2, B120, "Wood panel B120"
3, C90, "Stylish tool box C90"
4, M500, "Wood cutter M500"
And a "ProductComponent" table as follows:
Hierarchy, ComponentID, Amount
0301, 1, 24
0302, 2, 6
0401, 1, 3
0402, 3, 1
0403, 4, 1
040201, 1, 24
040202, 2, 6
The trick is: field hierarchy is a VARCHAR with first 2 chars representing each product's ID, each next pair of chars identify a node in the tree. So we see that product 3 depends on 2 other products. Product 4 depends on 2 others, also, one of which depends on its part on two others.
There's lots of redundancy in this model, but allows to easily calculate how many screws you need for a particular product, determine fastly which parts need wood panels or get the list of all components a product ultimately depends on (including indirect dependencies), etc. And scanning the tree below a certain level is a simple LIKE query!
By using 2 chars in a hexadecimal representation I limited a product to depend directly on maximum 256 other prods (which on turn can depend on something else). You could change that to use base 36 (the 26 letters plus 10 numbers) or base-64 if you need more than that.
Besides, this table model works very well on Access and mySQL, too. What you can not have is circular dependencies in any way.
SQL is not very good at walking arbitrary depth hierarchies.
If there's less than 1000 of these records, I would grab them all to the application and construct the graph there.
If there's more than 1000 of these records, I'd group them into raw subtrees of approx 1000 (by adding a SubtreeID foreign key) and fetch each subtree... then construct the graph of the subtree in the application.
The first thing I'd do is strip out the destination column - it's meaningless in terms of hierarchy (it actually appears to be a kind of second primary key to signal a live child row the way you've represented it)
this would give
ID, Item, parentID
1, Applications, (null)
2, Games, (null)
3, Office, 1
4, Text Editing, 1
5, Media, (null)
6, Word, 3
7, Excel, 3
8, Crysis, 2
e.g...
word > office > applications and...
excel > office > applications
...should presumably be on the same menu item (parent id 3)
I'm not sure how you're selecting the menu but I'll work on the principle that there's an initial menu button set with (null) as it's parameter and each subsequent click holds the next parameter in sequence dynamically (which seems to match your comments)
e.g.
click top level menu :- value is (null)
click applications :- value is 1
click Office :- value is 3
etc.
Assuming the destinationID is doing nothing apart from showing an active child link (allowing you to remove it), the code would then be as follows:
with items (nodeID, PID, list) as
(select id, ParentID, item
from menu
where id = 9
union all
select id, ParentID, item
from menu
inner join items on nodeID = menu.ParentID
)
select *
from items
where (pid = 9)
and nodeID in (select parentid from menu)
This works in MSSQL 2005+
If you need the destination id for some other reason then you can amend the code as follows (if you need to return the lowest level where a node id hasn't been set as a parent id, for instance):
with items (nodeID, PID, list, dest) as
(select id, ParentID, item, destinationID
from menu
where id = 9
union all
select id, ParentID, item, destinationID
from menu
inner join items on nodeID = menu.ParentID
)
select *
from items
where (pid = 9)
and (nodeID in (select parentid from menu)
or dest is not null)
https://geeks.ms/jirigoyen/2009/05/22/recursividad-con-sql-server/
ALTER PROCEDURE [dbo].[Usuarios_seguridad_seleccionar]
AS
BEGIN
DECLARE #minClave int
SELECT #minClave = MIN(Clave) FROM dbo.Usuarios_seguridad;
WITH UsuariosAccesos AS(
SELECT top 1 us1.Padre,us1.Clave,us1.Variable,us1.Modulo,us1.Contenido,us1.Acceso,us1.Imagen
FROM dbo.Usuarios_seguridad us1
WHERE us1.Clave = #minClave
UNION ALL
SELECT top 100 percent us2.Padre,us2.Clave,us2.Variable,us2.Modulo,us2.Contenido,us2.Acceso,us2.Imagen
FROM dbo.Usuarios_seguridad us2
INNER JOIN UsuariosAccesos AS us3 ON us3.Clave = us2.Padre
WHERE us2.Clave <> #minClave
)
SELECT TOP 100 PERCENT ia.Padre,ia.Clave,ia.Variable,ia.Modulo,ia.Contenido,ia.Acceso,ia.Imagen
FROM UsuariosAccesos ia
ORDER BY padre, clave
END
GO
I have inherited a very old database that needs some data to be updated. Each row ha a column with a UniqueID that looks like C0042-45-39612. The last 3 numbers of the code are the category Id (in this case 612).
I need to do an update that targets only certain categories and I'm using this SQL statement
UPDATE WebbikesProducts SET Price = Price * 1.05 WHERE Convert( Integer, SubString( UniqueID, 3, 3 )) = 125
The obvious problem here is what if the unique code doesn't have 3 numbers at the end? Well that's exactly the problem I have as not all the items are categorized or have unique numbers like C0049-307-1CHROME.
I don't have access to the DB (I'm calling this from an asp page) so I'd prefer not to have to create a stored procedure. The DB is SQL 2000.
Is there any way to ignore the rows with errors and carry on updating the other rows?
Try this:
UPDATE WebbikesProducts
SET Price = Price * 1.05
WHERE ISNUMERIC(SubString( UniqueID, 3, 3 )) = 1
AND Convert( Integer, SubString( UniqueID, 3, 3 )) = 125
or even more simple:
UPDATE WebbikesProducts
SET Price = Price * 1.05
WHERE SubString( UniqueID, 3, 3 ) = '125'
-Edo
I'm not sure why you are bothering converting to an int. Why not just do a string compare for the last three digits. Also, you are doing - substring(id, 3, 3).
I assume you have simplified the above snippet to make it easier to read and that you are already extracting the 39612 first?
I would suggest the following:
where UniqueID like '%612'