I am having an issue while being left joining 2 tables using subquery, getting an error :
Msg 156, Level 15, State 1, Line 25
Incorrect syntax near the keyword 'FROM'.
Msg 102, Level 15, State 1, Line 36
Incorrect syntax near 'PM'.
Here is the query I was trying to achieve:
SELECT
[SEASON],
SUM(B.QUANTITY) AS QUANTITY,
FROM
(SELECT
QUANTITY, WAREHOUSE,
CASE SUBSTRING(sku, 3, 1)
WHEN '1' THEN 'SS'
ELSE 'FW'
END + SUBSTRING (sku, 1, 2) [SEASON]
FROM
Table
) B
As I stated in the comments, you have 2 FROM clauses. Presumably the latter should be a CROSS JOIN or CROSS/OUTER APPLY (we don't know which). You also alias your second derived table as PM and then alias the table PRODTABLE as PM; that isn't allowed either as you can't have 2 objects with the same alias in the same scope. As I can't guess what alias you mean in other locations, I put {Alias} in places you need to add the relevant alias.
I also remove the NOLOCK table hints; you didn't reply as to why you "need" them and with respect I doubt you understand what it does considering the comments and question; more likely you have picked up someone elses terrible habit (get rid of said bad habit now).
I also, finally, get rid of the other bad habit of single quote aliases (see my comment on that too) and schema qualify (assuming dbo):
SELECT {Alias}.[SEASON],
SUM(BL.QUANTITY) AS QUANTITY,
{Alias}.PRODUCT AS PRD_CLASS,
{Alias}.BRAND AS BRAND,
{Alias}.COST_PRICE AS COST,
{Alias}.DATECREATE
FROM (SELECT QUANTITY,
WAREHOUSE,
CASE SUBSTRING(EXTENDED, 3, 1)WHEN '1' THEN 'SS' ELSE 'FW' END + SUBSTRING(EXTENDED, 1, 2) AS [SEASON]
FROM dbo.BINLABE) BL
CROSS JOIN (SELECT PRODUCT AS PRDODUCT,
BRAND AS BRAND,
COST_PRICE AS COST,
DATECREATE AS DATE_CREATE
FROM dbo.PRODTABLE) PT
LEFT JOIN dbo.PRODTABLE PM ON BL.SKU = PM.SKU --Think we can safely assume this is PM
WHERE {Alias}.WAREHOUSE = '0001'
GROUP BY {Alias}.[SEASON]
ORDER BY {Alias}.[SEASON];
Related
I got this error message when I tried to run this code
select *
from Folio_Guest
where FolioID = (
select *
from Folio
where ArrivalDate between '20190101' and '20210901'
)
The subquery needs to return at most one row and only one column. Perhaps you intend something like this:
select fg.*
from Folio_Guest fg
where fg.FolioID in (select f.folioID
from Folio f
where ArrivalDate between '20190101' and '20210901'
);
The important changes are:
The subquery returns just one column, the one that should match to folioID.
The comparison uses in rather than = so it can match multiple rows, if appropriate.
Hello friendly internet wizards.
I am attempting to extract a levelled bill of materials (BOM) from a dataset, running in DB2 on an AS400 server.
I have constructed most of the query (with a lot of help from online resources), and this is what I have so far;
#set item = '10984'
WITH BOM (origin, PMPRNO, PMMTNO, BOM_Level, BOM_Path, IsCycle, IsLeaf) AS
(SELECT CONNECT_BY_ROOT PMPRNO AS origin, PMPRNO, PMMTNO,
LEVEL AS BOM_Level,
SYS_CONNECT_BY_PATH(TRIM(PMMTNO), ' : ') BOM_Path,
CONNECT_BY_ISCYCLE IsCycle,
CONNECT_BY_ISLEAF IsLeaf
FROM MPDMAT
WHERE PMCONO = 405 AND PMFACI = 'M01' AND PMSTRT = 'STD'
START WITH PMPRNO = :item
CONNECT BY NOCYCLE PRIOR PMMTNO = PMPRNO)
SELECT 0 AS BOM_Level, '' AS BOM_Path, MMITNO AS Part_Number, MMITDS AS Part_Name,
IFSUNO AS Supplier_Number, IDSUNM AS Supplier_Name, IFSITE AS Supplier_Part_Number
FROM MITMAS
LEFT OUTER JOIN MITVEN ON MMCONO = IFCONO AND MMITNO = IFITNO AND IFSUNO <> 'ZGA'
LEFT OUTER JOIN CIDMAS ON MMCONO = IDCONO AND IDSUNO = IFSUNO
WHERE MMCONO = 405
AND MMITNO = :item
UNION ALL
SELECT BOM.BOM_Level, BOM_Path, BOM.PMMTNO AS Part_Number, MMITDS AS Part_Name,
IFSUNO AS Supplier_Number, IDSUNM AS Supplier_Name, IFSITE AS Supplier_Part_Number
FROM BOM
LEFT OUTER JOIN MITMAS ON MMCONO = 405 AND MMITNO = BOM.PMMTNO
LEFT OUTER JOIN MITVEN ON IFCONO = MMCONO AND IFITNO = MMITNO AND IFSUNO <> 'ZGA' AND MMMABU = '2'
LEFT OUTER JOIN CIDMAS ON MMCONO = IDCONO AND IDSUNO = IFSUNO
;
This is correctly extracting the components for a given item, as well as the sub-components (etc).
Current data looks like this (I have stripped out some columns that aren't relevant to the issue);
https://pastebin.com/LUnGKRqH
My issue is the order that the data is being presented in.
As you can see in the pastebin above, the first column is the 'level' of the component. This starts with the parent item at level 0, and can theoretically go down as far as 99 levels.
The path is also show there, so for example the second component 853021 tells us that it's a 2nd level component, the paths up to INST363 (shown later in the list as a 1st level), then up to the parent at level 0.
I would like for the output to show in path order (for lack of a better term).
Therefore, after level 0, it should be showing the first level 1 component, and then immediately be going into it's level 2 components and so on, until no further level is found. Then at that point, it returns back up the path to the next valid record.
I hope I have explained that adequately, but essentially the data should come out as;
Level
Path
Item
0
10984
1
: INST363
INST363
2
: INST363 : 853021
853021
1
: 21907
21907
Any help that can be provided would be very much appreciated!
Thanks,
This is an interesting query. Frankly I am surprised it works as well as it does since it is not structured the way I usually structure queries with a recursive CTE. The main issue is that while you have the Union in there, it does not appear to be within the CTE portion of the query.
When I write a recursive CTE, it is generally structured like this:
with cte as (
priming select
union all
secondary select)
select * from cte
So to get a BOM from an Item Master that looks something like:
CREATE TABLE item (
ItemNo Char(10) PRIMARY KEY,
Description Char(50));
INSERT INTO item
VALUES ('Item0', 'Root Item'),
('Item1a', 'Second Level Item'),
('Item1b', 'Another Second Level Item'),
('Item2a', 'Third Level Item');
and a linkage table like this:
CREATE TABLE linkage (
PItem Char(10),
CItem Char(10),
Quantity Dec(5,0),
PRIMARY KEY (PItem, CItem));
INSERT INTO linkage
VALUES ('Item0', 'Item1a', 2),
('Item0', 'Item1b', 3),
('Item1b', 'Item2a', 5)
The recursive CTE to list a BOM for 'Item0' looks like this:
WITH bom (Level, ItemNo, Description, Quantity)
AS (
-- Load BOM with root item
SELECT 0,
ItemNo,
Description,
1
FROM Item
WHERE ItemNo = 'Item0'
UNION ALL
-- Retrieve all child items
SELECT a.Level + 1,
b.CItem,
c.Description,
a.Quantity * b.Quantity
FROM bom a
join linkage b ON b.pitem = a.itemno
join item c ON c.itemno = b.citem)
-- Set the list order
SEARCH DEPTH FIRST BY itemno SET seq
-- List BOM
SELECT * FROM bom
ORDER BY seq
Here are my results:
LEVEL
ITEMNO
DESCRIPTION
QUANTITY
0
Item0
Root Item
1
1
Item1a
Second Level Item
2
1
Item1b
Another Second Level Item
3
2
Item2a
Third Level Item
15
Notice the search clause, that generates a column named seq which you can use to sort the output either depth first or breadth first. Depth first is what you want here.
NOTE: This isn't necessarily an optimum query since the description is in the CTE, and that increases the size of the CTE result set without really adding anything to it that couldn't be added in the final select. But it does make things a bit simpler since the 'priming query' retrieves the description.
Note also: the column list on the with clause following BOM. This is there to remove the confusion that DB2 had with the expected column list when the explicit column list was omitted. It is not always necessary, but if DB2 complains about an invalid column list, this will fix it.
I have the next data base:
Table Bill:
Table Bill_Details:
And Table Type:
I want a query to show this result:
The query as far goes like this:
SELECT
Bill.Id_Bill,
Type.Id_Type,
Type.Info,
Bill_Details.Deb,
Bill_Details.Cre,
Bill.NIT,
Bill.Date2,
Bill.Comt
FROM Type
RIGHT JOIN (Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill)
ON Type.Id_Type = Bill_Details.Id_Type
ORDER BY Bill.Id_Bill, Type.Id_Type;
With this result:
I'm not sure how to deal or how to include this:
Type.600,
Type."TOTAL",
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) >= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), "" ),
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) <= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), "" )
The previous code is the responsable of include new data in some fields, since all of the other fields will carry the same data of the upper register. I'll apreciate some sugestions to acomplish this.
Here is a revised version of the UNION which you removed from the question. The original query was a good start, but you just did not provide sufficient details about the error or problem you were experiencing. My comments were not meant to have you remove the problem query, only that you needed to provide more details about the error or problem. In the future if you have a UNION, make sure the each query of the UNION works separately. Then you could debug problems easier, one step at a time.
Problems which I corrected in the second query of the UNION:
Removed reference to table [Type] in the query, since it was not part of the FROM clause. Instead, I replaced it with a literal value.
Fixed FROM clause to join both [Bill] and [Bill_Details] tables. You had fields from both tables, so why would you not join on them just like in the first query of the UNION?
Grouped on all fields from table [Bill] referenced in the SELECT clause. You must either group on all fields, or include them in aggregate expressions like Sum() or First(), etc.
Replaced empty strings with Nulls for the False cases on Iif() statements.
SELECT
Bill.Id_Bill, Type.Id_Type, Type.Info,
Bill_Details.Deb,
Bill_Details.Cre,
Bill.NIT, Bill.Date2, Bill.Comt
FROM
Type RIGHT JOIN (Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill)
ON Type.Id_Type = Bill_Details.Id_Type;
UNION
SELECT
Bill.Id_Bill, 600 As Id_Type, "TOTAL" As Info,
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) >= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), Null ) As Deb,
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) <= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), Null ) As Cre,
Bill.NIT, Bill.Date2, Bill.Comt
FROM Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill
GROUP BY Bill.Id_Bill, Bill.NIT, Bill.Date2, Bill.Comt;
When I execute this query in SQL Server Management Studio, this error appears:
'Msg 207, Level 16, State 1, Line 1
Invalid column name 'ACCOUNT_NO'.'
This is the code for the query:
DECLARE #largeaccnumber INT = ACCOUNT_NO
DECLARE #smallaccnumber INT
SET #smallaccnumber = (SELECT LEFT(#largeaccnumber, 6))
SELECT DNADRX.CODE,
DNADDR.NAME,
DNADDR.TYPE,
DNADDR.MAIL_NAME,
ADDRESS_LINE1,
ADDRESS_LINE2,
ADDRESS_LINE3,
TOWN_CITY,
COUNTY_STATE,
COUNTY_STATE_CODE,
COUNTRY,
POST_ZIP,
LAST_STAT_DATE,
ACCOUNT_NO
FROM DNADRX,
DNADDR,
BACCNT
WHERE DNADDR.CODE = DNADRX.ADDRESS_CODE
AND DNADDR.CODE = #smallaccnumber
ORDER BY DNADRX.CODE
I want the query to display the data from the columns of the different tables (the columns are listed in the SELECT bit of the query) from 3 different tables (DNADRX, DNADDR, BACCNT), and the factor linking all 3 tables together is the 6 digit code (ACCOUNT_NO in the BACCNT table, ADDRESS_CODE in the DNADRX table and CODE in the DNADDR table). Originally, ACCOUNT_NO from table BACCNT was 8 digits long, but I reduced it to the first 6 digits using SELECT LEFT and assigned this 6 digit value to the variable #smallaccnumber.
Whenever I try to execute the query, it keeps telling me that 'ACCOUNT_NO' is an invalid code name. I have checked the spelling, refreshed using IntelliSense and tried 'BACCNT.ACCOUNT_NO' instead of just 'ACCOUNT_NO' on the first line of the query but it still won't work (instead it says that the multi-part identifier could not be bound when I try 'BACCNT.ACCOUNT_NO').
I am really new to SQL coding so sorry if the answer to my problem is really simple.
Thank you for your assistance :)
You can try something like this.
This assumes you know the 6 character code. This query will only find results IF there is a record matching in EVERY table. If one table doesn't find a matching record this query will return NOTHING. If you want to find a row even if a recrod is missing from a table, replace the "INNER JOIN" with "LEFT OUTER JOIN"
SELECT Dnadrx.Code,
Dnaddr.Name,
Dnaddr.Type,
Dnaddr.Mail_Name,
Address_Line1,
Address_Line2,
Address_Line3,
Town_City,
County_State,
County_State_Code,
Country,
Post_Zip,
Last_Stat_Date,
Account_No
FROM Dnaddr
INNER JOIN BACCNT ON DNAADDR.CODE = BACCNT.ACCOUNT_NO
INNER JOIN Dnadrx ON Dnaaddr.Code=Dnaadrx.Address_Code
WHERE Dnaddr.Code='YOUR 6 CHARACTER CODE GOES HERE'
ORDER BY Dnadrx.Code;
I have an SQL function which returns the minimum and maximum selling price of an item. I'd like to make a query which gets other StockItem columns together with it's selling price
like so:
SELECT i.StockItemID ii,
i.Name,
i.Code,
pli.SellingPrice AS MinSellingPrice,
pli.StandardSellingPrice AS MaxSellingPrice,
i.WebDetailedDescription,
i.WebAdditionalInfo,
i.FeaturedItemDescription
FROM SC_StockItem AS i,
func_GetPrice(17, i.StockItemID, 5) pli
However this gives an error:
Msg 4104, Level 16, State 1, Line 12 The multi-part identifier
"i.StockItemID" could not be bound.
any idea how I can do this ?
Thanks in advance
If that is a table valued function, then you can use OUTER APPLY:
select i.StockItemID ii,
i.Name,
i.Code,
pli.SellingPrice as MinSellingPrice,
pli.StandardSellingPrice as MaxSellingPrice,
i.WebDetailedDescription,
i.WebAdditionalInfo,
i.FeaturedItemDescription
from SC_StockItem as i
OUTER APPLY func_GetPrice(17, i.StockItemID, 5) pli
From MSDN:
The APPLY operator allows you to invoke a table-valued function for each row returned by an outer table expression of a query.