How to show integer value column to be string value in display using SQL - sql

My sale table
ID Sales Amount
--------------------
101 1 1000
102 1 1500
103 2 2000
104 3 2500
In the above table Sales column 1 refer to 'keyboard' 2 refer to 'Mouse' and 3 refer to 'CD'.
If i use SELECT * FROM Sale WHERE ID=103
it will return
ID Sales Amount
------------------
103 2 2000
but I need to display like below
ID Sales Amount
------------------
103 Mouse 2000
In db i need to store sales value as int like '1,2,3,4,5' but when show to user i need to display a unique string value for each integer value.

SELECT
ID,
CASE Sales
When 1 Then 'KeyBoard'
When 2 Then 'Mouse'
When 3 Then 'CD'
END AS Sales,
Amount
FROM
Sale
WHERE
Id = 103

I suggest you to create a table like this:
[Table: SaleType]
+----+----------+
| Id | Name |
+----+----------+
| 1 | Keyboard |
| 2 | Mouse |
| 3 | CD |
: .. : ... :
+----+----------+
And set the Sales column in Sale tables a Foreign Key(FK) of SaleType, then you can have your result by using this query:
SELECT
Sale.ID,
SaleType.Name,
Sale.Amount
FROM
Sale
JOIN
SaleType ON Sale.Sales = SaleType.Id

Related

Database Design: Inventory with multilevel packaging

I'm trying to develop a database for my inventory. But I have no idea how to keep track of multilevel packaging.
For example:
I currently have a products and positions table
products
Id | Name
================
1013 | Metal
1014 | Wood
positions
id | Name
================
1 | 1-1-1-1
2 | 1-1-1-2
And my inventory table I was thinking of doing something like this:
Let's say I stored 1 box with 1000 Metal and 1 box with 500 Wood at position 1-1-1-1
ItemId | ProductId | Quantity | PositionId
==========================================
1 | 1013 | 1000 | 1
2 | 1014 | 500 | 1
So I'll label those two boxes with a barcode 1 and 2 respectively, so if I scan them, I can check this table to see the product and quantity inside them.
But I can also put these 2 boxes (1 and 2) inside another box (let's call it box 3), which would generate a new barcode for it that, if scanned, will show both previous boxes and its items. And store this box 3 in another position
And I can also put this box 3 inside a pallet, generating a new code and so on. So basically I can multilevel package N times.
What is the best table structure to keep track of all of this? Thanks in advance for any help!
I would add another column to the products table, make it a BIT and maybe call it BOM, BillOfMaterials, or whatever makes sense to you
So your products Table would look like this
Then you could create another table called BillOfMaterials
Quantity is how many of your products are needed to make up your new product. So for this example 2 metal and 1 wood make a pencil.
I was able to make a good structure:
My products and positions are the same but I created a stock table like:
id | product_id | amount | parent_id | position_id
=====================================================
1 | 1013 | 1000 | 4 | 1
2 | 1013 | 1000 | 4 | 1
3 | 1014 | 500 | 4 | 1
4 | 1234 | NULL | NULL | 1
The 1234 (random id) is a box that contains 2000 metal and 500 wood. I dont save this box in the product table.
When I scan the box with id 3, I perform a recursive cte query:
with recursive bom as (
select *, 1 as level
from testing.stock
where id = '4' #scanned id
union all
select c.*, p.level + 1
from testing.stock c
join bom p on c.parent_id = p.id
)
select product_id as product, sum(amount), position_id
from bom b
left join testing.product pd on b.product_id = pd.id
where pd.id is not null
group by product_id, position_id
which returns:
sum | product | position
2000 | 1013 | 3
500 | 1014 | 3
to get by position I just run a variation of the above query. To perform an update I get the Ids inside that box and run a
update testing.stock set position = '2' where id in (#variation of above query)
I hope this helps someone. This works for N packaging level

How to insert a Number value which is a difference between field 1 and field 2 of another table in Oracle?

I have a table name ITEM that consist of
+-------+-----------+--------------+
| Item | PrevValue | CurrentValue |
+-------+-----------+--------------+
| ItemA | 2 | 10 |
| ItemB | 1 | 2 |
+-------+-----------+--------------+
And another table name PAYMENT that will require insert.
INSERT INTO PAYMENT(ID, Billing_Date, Due_Date, Value_Amount)
VALUES (1,TO_DATE('23-JULY-2020','DD-MON-YYYY'), TO_DATE('21-AUGUST-2020','DD-MON-YYYY'),
**CurValue - PrevValue** );
How do i correctly calculate the differences between PrevValue and CurValue in ITEM and insert them into PAYMENT?
The query will be, simply INSERT....SELECT:
INSERT INTO PAYMENT(ID, Billing_Date, Due_Date, Value_Amount)
select 1,TO_DATE('23-JULY-2020','DD-MON-YYYY'), TO_DATE('21-AUGUST-2020','DD-MON-YYYY'), (CurValue - PrevValue) from ITEM where Item = '<Item_Name>';

SQL Insert when not exist Update if exist with mutliple rows in Target-Table

I have two tables, where table A has to be Updated or insert a row base on existing. I tried this by using JOINS EXCEPT and MERGE statement but I have one problem i can't solve. so here is an example :
Table A (Attribut-Table)
attr | attrValue | prodID
--------------------------
4 | 2 | 1
--------------------------
3 | 10 | 2
--------------------------
1 | 7 | 2
--------------------------
3 | 10 | 3
--------------------------
6 | 9 | 3
--------------------------
1 | 4 | 3
--------------------------
Table P(Product-Table)
prodID | stock |
------------------
1 | 1
------------------
2 | 0
------------------
3 | 1
------------------
4 | 1
------------------
Now what i would like to do the following in SQL:
All products, that has Stock > 0 should have an entry in Table A with attr = 6 and attrValue = 9
All products, that has Stock < 1 should have an entry in Table A with attr = 6 and attrValue = 8
i need a SQL Query to do that because my problem is that there are multiple entries for a prodID in Table A
That is what i am thinking of:
Fist check if any entry for the prodID(in Table B) exist in Table A, if not INSERT INTO Table A ( attr=6 and, attrValue = 8/9 (depends on Stock), prodID
If there is already an entry for the prodID in Table A with the attr = 6, then Update this row and set attrValue to 8/9 (depending on stock)
so I am looking for a translation of "my thoughts" to a sqlQuery
thanks for helping.
(using: SQL SERVER Express 2012 and HEIDI SQL for management)
Since your "attr 6" row is 100 % derivable from the state of the P table, it is a poor idea to store that row redundantly in A.
This is better :
(1) Define a first view ATTR6_FOR_P as SELECT prodID, 6 as attr, CASE (...) as attrValue from P. The CASE expression chooses the value 8 or 9 according to stock value in P.
(2) Define a second view A_EXT as A UNION ATTR6_FOR_P. (***)
Now changes in stock will always immediately be reflected in A_EXT without having to update explicitly.
(***) but beware of column ordering because SQL UNION does not match columns by name but by ordinal position instead.

Select rows with same value in one column but different value in another column

I've been trying to build this query but am new to SQL so I'd really appreciate some help.
In the below table example, I have a Customer Code, a linked Customer Code (which is used to link a child customer to a parent customer), a salesperson, and other irrelevant columns. The goal is to have one Salesperson for each parent customer and it's children. So in the example, CustCode #100 is the parent of itself, #200, #500, and #800. All of these accounts have the same Salesperson (JASON) which is perfect. But for CustCode #300, it is the parent of itself, #400, and #600. However, there isn't one salesperson assigned - its both JIM and SUZY. I want to build a query that shows all accounts for this example. Basically, accounts where the Salesperson field isn't the same value for all of it's child customers.
I tried a Where clause for Salesperson <> Salesperson but its not showing up right.
+-----------+-----------------+------------+----------------------+
| CustCode | Linked CustCode | Salesperson| additional columns...|
+-----------+-----------------+------------+----------------------+
| 100 | 100 | JASON | ... |
| 200 | 100 | JASON | ... |
| 300 | 300 | JIM | ... |
| 400 | 300 | JIM | ... |
| 500 | 100 | JASON | ... |
| 600 | 300 | SUZY | ... |
| 700 | NULL | JIM | ... |
| 800 | 100 | JASON | ... |
+-----------+-----------------+------------+----------------------+
Thanks so much for your help!
You can do self join on the table.
select distinct r2.* from
table r1
join table r2
on
r1.linkedcustcode = r2.linkedcustcode and r1.salesperson <> r2.salesperson
This solution uses a recursive CTE first to build the hierarchy and find the leading code for each row, even if a linked code points to a row which is pointing to an upper row itself.
The final query shows the count of different Salespersons:
DECLARE #tbl TABLE(CustCode INT,[Linked CustCode] INT,Salesperson VARCHAR(100));
INSERT INTO #tbl VALUES
(100,100,'JASON')
,(200,100,'JASON')
,(300,300,'JIM')
,(400,300,'JIM')
,(500,100,'JASON')
,(600,300,'SUZY')
,(700,NULL,'JIM')
,(800,100,'JASON');
--The query
WITH CleanUp AS
(
SELECT CustCode
,CASE WHEN [Linked CustCode]=CustCode THEN NULL ELSE [Linked CustCode] END AS [Linked CustCode]
,Salesperson
FROM #tbl
)
,recCTE AS
(
SELECT CustCode AS LeadingCode,CustCode,[Linked CustCode],Salesperson
FROM CleanUp
WHERE [Linked CustCode] IS NULL
UNION ALL
SELECT recCTE.LeadingCode,t.CustCode,t.[Linked CustCode],t.Salesperson
FROM recCTE
INNER JOIN CleanUp AS t ON t.[Linked CustCode]=recCTE.CustCode
)
SELECT LeadingCode,COUNT(DISTINCT Salesperson) AS CountSalesperson
FROM recCTE
GROUP BY LeadingCode
The result
LeadingCode CountSalesperson
100 1
300 2
700 1

Grouping by partial value

I'm very new to SQL and I have no clue how to even begin with this one.
I've got two tables: Warehouse and Items. Here's how they look like(simplified):
Warehouse
ItemID | QuantityInStock | QuantityOnOrder | QuantityOnOrder2 | QuantityOnOrder3 | QuantityOnOrder4
-------+-----------------+-----------------+------------------+------------------+-----------------
1111 | 8 | 1 | 0 | 1 | 0
2222 | 3 | 0 | 0 | 0 | 0
3333 | 4 | 0 | 1 | 0 | 0
Items
ItemID | Code
-------+-----------------
1111 | abc123456-111-01
2222 | abc123456-111-02
3333 | abc123457-112-01
What I need to return via SQL query is this:
ShortCode | Quantity
----------+---------
abc123456 | 9
abc123457 | 3
ItemID is the key to join both tables
Code in the Items table include main product code (abc123456) and variants (-111-01). I need to group the lines by main product code only
Quantity I need comes from Warehouse table and it equals "QuantityInStock - QuantityOnOrder - QuantityOnOrder2 - QuantityOnOrder3 - QuantityOnOrder4". Using this we get abc123456 (comes in two variants in Items table with ItemId 1111 and 2222) and Quantity is equal 8 minus 1 minus 0 minus 1 minus 0 for 1111, and 3 minus 0 minus 0 minus 0 minus 0 for 2222 which together gives 9
This is probably the worst explanation ever, so I hope there is someone that can understand it.
Please help.
Assuming that you can always count on matching the first 9 characters of the Code column then the following query should work.
/// note that the SUM method may return a negative (-) number
SELECT LEFT(I.[Code], 9) AS 'ShortCode', SUM([QuantityInStock] - [QuantityOnOrder] - [QuantityOnOrder2] - [QuantityOnOrder3] - [QuantityOnOrder4]) AS 'Quantity'
FROM [dbo].[Warehouse] AS W
INNER JOIN [dbo].[Items] AS I ON I.[ItemId] = W.[ItemId]
GROUP BY LEFT(I.[Code], 9)
Using standard SQL:
SELECT
LEFT(Items.Code, 9) AS ShortCode,
SUM(T.remaining) AS Quantity
FROM Items
JOIN (
SELECT
ItemID,
QuantityInStock - QuantityOnOrder - QuantityOnOrder2 - QuantityOnOrder3 - QuantityOnOrder4 AS remaining
FROM Warehouse
) AS T ON (T.ItemID = Items.ItemID)
GROUP BY LEFT(Items.Code, 9);
Not tested, but should work. Only potential issue is that you use uppercase letters in your table and column names, so you might have to enclose all table and column names in backticks (`) or square brackets depending on your DB server.
EDIT: If you want to filter those with less than a certain number of pieces left, just add:
HAVING SUM(T.remaining) > xxx
Where xxx is the minimum quantity you want