Need to do tthis in 1 SQL - sql

I have to process in an sql as follows. each order is made up of many detail rows. I only need to look at one table, TRA99.
Order number TRAN CODE
123 QEE
123 #23
123 ABC
SELECT
ALL OTRIDC, OTCOM#, OTORD#, OTFL50, OTTRND, OTTRT, OTENT#,
OTSFX#,
OTREL#, OTUSRN, OTTRNC, OTTRN$, OTFL01
FROM ASTDTA.OETRANOT T01
WHERE OTTRNC IN ('QEE', 'QNE')
I want all the Order # which have 'QEE' or 'QNE'. These are QUote codes. We want a report that will tell us, which quotes orders' converted to a real order and which did not.
then if they have as well #23, this tells me that the order was converted or became an actual order. I am not sure how to do this in 1 sql query i was thinking to create a view for all QEE and QNE codes. then run a second query against that looking for #23.

Based on what I think you're trying to do. This will give you all the order numbers which are associated with both QEE or QNE and #23
SELECT T1.OrderNumber
FROM TRA99 T1
WHERE T1.OrderNumber in (
SELECT OrderNumber
FROM TRA99
WHERE TCode IN ('QEE','QNE')
)
AND T1.TCode='#23'
GROUP BY T1.OrderNumber

What you need to do is use a GROUP BY also a EXISTS sub-query can check for the existence of your flag
select t1.[Order Number]
,(CASE WHEN EXISTS(select *
from TRA99 as t2
where t1.[Order Number] = t2.[Order Number]
and t2.[Tran Code] = '#23')
THEN
cast(1 as bit)
ELSE
cast(0 as bit)
END) as HasFlag
from TRA99 as t1
where t1.[Tran Code] in ('QFE', 'QNE')
group by t1.[Order Number]
Working example
NOTE: you did not list what DBMS you are using so I wrote this against Microsoft Sql Server syntax, but you can translate this concept to any DBMS you need.

Related

Different results in SQL based on what columns I display

I am trying to run a query to gather the total items on hand in our database. However it seems i'm getting incorrect data. I am selecting selecting just the amount field and summing it using joins from separate tables based on certain parameters, however if I display additional fields such as order number, and date all of a sudden im getting different data, even though those fields are being used as filters in the query. Is it because its not in the select statement? If it needs to be in the select statement is it possible to not display them?
Here are the two queries.
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt'
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
providing a sum of 21667457.20
and with the added columns
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt', [Requested Delivery Date], sh.No_, tw.[Status]
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
group by sh.[Requested Delivery Date], sh.No_, tw.[Status]
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
order by sh.[Requested Delivery Date] ASC
Providing a sum of 12319998
I'm self taught in SQL so I may be misunderstanding something obvious, thanks for the help.
With no sample data, I am going to have to demonstrate this in principle. In the latter query you have a GROUP BY meaning the scope of the values in the HAVING will differ, and thus the filtering from said HAVING will be different.
Let's take the following sample data:
CREATE TABLE dbo.MyTable (Grp char(1),
Quantity int,
Required int);
INSERT INTO dbo.MyTable (Grp, Quantity, [Required])
VALUES('a',2,7),
('a',14,2),
('b',4, 7),
('b',3,4),
('c',17,5);
Now we'll perform an overly simplified version of your query:
SELECT SUM(Quantity)
FROM dbo.MyTable
HAVING SUM(Quantity) > SUM(Required);
This brings back the value 40; which is the SUM of all the values in Quantity. A value is returned because the total SUM of Required is 25.
Now let's add a GROUP BY like your second query:
SELECT SUM(Quantity)
FROM dbo.MyTable
GROUP BY Grp
HAVING SUM(Quantity) > SUM(Required);
Now we have 2 rows, with the values 16 and 17 giving a total value of 33. That's because the rows where Grp have a value of 'B' are filtered out, as the SUM of Quantity is lower that Required for 'B'.
The same is happening in your data; in the grouped data you have groups where the HAVING condition isn't met, so those rows aren't returned.

Asking to enter a parameter value that already exists

I have a three column table of price breaks called "FPB" that looks like this:
[Part Number] [Quantity] [Price]
AAA-AAAA     100   1.23
AAA-AAAA     200   1.15
BBB-BBBB     100   5.60
CCC-CCCC      500   3.21
....
Where each part number has multiple entries in multiple rows.
I'm trying to reorganize the table to look more like this
[Part Number] [Quantity1] [Price 1] [Quantity 2] [Price 2] [Quantity 3....
AAA-AAAA      100   1.23    200    1.15   ....
BBB-BBBB      100   5.60     ...
CCC-CCCC       500   3.21    ...
...
Where each part number has all its entries combined into one row. The first quantity column should have the lowest available quantity, the second should have the second smallest etc. I am trying to do this by first creating a 1-column table with just the unique part numbers using GROUP BY, and then creating more tables for each column that has the information I want in that column, and then joining it by Part Number. The problem comes when calculating the second smallest quantity for each type, done in the second to last section.
SELECT PNs.[Part Number], Q1T.Q1, P1T.Price, Q2T.Q2
FROM
(SELECT
[Part Number]
FROM FPB
GROUP BY [Part Number]
) AS PNs,
(SELECT
[Part Number],
MIN(Quantity) AS Q1
FROM FPB
GROUP BY [Part Number]
) AS Q1T,
(SELECT
*
FROM FPB
) AS P1T,
(SELECT
[Part Number],
MIN(IIF(Quantity>Q1T.Q1,Quantity)) AS Q2
FROM FPB
GROUP BY [Part Number]
) AS Q2T
WHERE
PNs.[Part Number] = Q1T.[Part Number]
AND P1T.[Part Number] = PNs.[Part Number]
AND P1T.Quantity = Q1T.Q1
AND Q2T.[Part Number] = PNs.[Part Number]
When I run this query, it asks me to enter a parameter value for Q1T.Q1, even though it already exists. If I remove the code section for Q2T, as well as any references to Q2, it will work without a problem, and it won't ask about a value for the other instances of Q1T.Q1. Why doesn't Q1T.Q1 have a value just for that section, and how can I fix it? As a side note, I'm using the SQL features of a program called PHPRunner, and its client doesn't support UPDATE/DELETE/INSERT/CREATE queries, UNION, and DISTINCT.
You're looking for something like this.
select
p1.PartNumber,
ifnull(max(p2.Quantity), 0) + 1 as LowerQuantity,
p1.Quantity as UpperQuantity,
p1.Price,
count(p2.PartNumber) + 1 as PriceTier
from
FPB p1 left outer join FPB p2
on p2.PartNumber = p1.PartNumber and p2.Quantity < p1.Quantity
From there it's easy to pivot in order to insert into a new table:
into into NewFPB (PartNumber, Quantity1, Price1, Quantity2, Price2, ...)
select
PartNumber,
min(switch(PriceTier = 1, UpperQuantity)) as Quantity1,
min(switch(PriceTier = 2, UpperQuantity)) as Quantity2, ...
min(switch(PriceTier = 1, Price)) as Price1,
min(switch(PriceTier = 2, Price)) as Price2, ...
from (
select
p1.PartNumber,
ifnull(max(p2.Quantity), 0) + 1 as LowerQuantity,
p1.Quantity as UpperQuantity,
p1.Price,
count(p2.PartNumber) + 1 as PriceTier
from
FPB p1 left outer join FPB p2
on p2.PartNumber = p1.PartNumber and p2.Quantity < p1.Quantity
) data
You might have to tweak it a little bit for Access to accept it. But the core ideas are there.
The query you call is incorrect.
Q1T is inner select statement , and in Q2T (other inner select statement) , you can't use any field from Q1T
The SQL Server raise error: Incorrect syntax near ')'.
To overcome this limitation , you should use Common Table Expressions CTE
for PNs, Q1T, P1T, Q2T
CTE is like dynamic view.
It's a new feature since sql 2008 and It's a very powerful.
review: https://technet.microsoft.com/en-us/library/ms190766(v=sql.105).aspx
Try to Draw a relational data model for these four CTE to be sure that a relation exist between them based on your where conditions.
I think the logic in this query may raise runtime error during execution:
e.g. The multi-part identifier "Q1T.Q1" could not be bound.
Edit:
For Ms-Access you can create four queries for: PNs, Q1T, P1T, Q2T every one is in a separate query, and the fifth query join these queries and add where conditions.
In this case you will not get any syntax error. and will get Data model with relation free :) .
As per your question, by the time you define the derived table Q2T, Q1T is still an invalid object. You need to try to work around this issue.
EDIT:
Suppose you only got 2-level columns to handle, the code is listed below, i tested it. It works well.
select q5.*,q3.quantity, q3.price
from
(select *
from FPB as Q1
where 0 = (select count(distinct(quantity)) from FPB as Q2 where Q2.quantity < Q1.quantity AND Q2.[part number] = Q1.[part number])) as Q5
,
(
select distinct(temp.[part number]),Q2.quantity, Q2.price from FPB as temp
left join
(select *
from FPB as Q4
where 1 = (select count(distinct(quantity)) from #test as Q2 where Q2.quantity < Q4.quantity AND Q2.[PART NUMBER] = Q4.[PART NUMBER])) as Q2
on temp.[PART NUMBER] = Q2.[PART NUMBER]
) as Q3
where Q5.[PART NUMBER] = Q3.[PART NUMBER]

SQL Server 2012 - assistance with self join or CTE

DBMS: SQL Server 2012
I have a table with the following columns
What I need to be able to do is figure out the NextCarDepartureTime. So for example, Car2 would depart at 9/30/2014 1:12 AM, Car3 would depart at 10/1/2014 12:10 AM. The ultimate goal is to figure out the difference in hours between CarDepartedDateTime and NextCarDepartedTime. So the end result would look like
Any help would be greatly appreciated! Thanks
You can use the LEAD analytic function introduced in SQL server 2012. This function access subsequent row from your table. So your query now look like this -
;WITH myCTE
AS ( SELECT T1.Year ,
T1.Month ,
T1.CarNumberID ,
T1.CarDepartedDateTime ,
T1.CarDepartedNumberID ,
LEAD(T1.CarDepartedDateTime) OVER ( ORDER BY T1.id ) AS [NextCarDepartureTime] ,
LEAD(T1.CarNumberID) OVER ( ORDER BY T1.id ) AS [NextCarNumberID]
FROM Test T1
)
SELECT * ,
DATEDIFF(HOUR, CarDepartedDateTime, NextCarDepartureTime) AS TurnAroundTime
FROM myCTE;
I have written one blog post for analytic function in my blog here : krishnrajrana.wordpress.com
This would be the basic syntax you would need:
SELECT
T1.Year, T1.Month, T1.CarNumberID, T1.CarDepartedDateTime, T1.NextCarNumberID,
T2.CarDepartedDateTime as [NextCarDepartureTime],
CONVERT(varchar,(T2.CarDepartedDateTime - T1.CarDepartedDateTime, 108) as [Turn Around Time]
FROM
DatabaseName..TableName T1
Left outer join DatabaseName..TableName T2 on T2.CarNumberID = T1.NextCarNumberID
Depending on other details in the table (Primary Keys, etc.) you may want to add details to the join filters and/or a WHERE clause.
There are various options available for how you want to format/display the [Turn Around Time] field using different values for the last parameter of the CONVERT function. See https://msdn.microsoft.com/en-us/library/ms187928.aspx for a list of different options.

SQL exclude all rows that with have certain value?

i have a table with these value, and here is a small sample
order state item id
10064315 ON MCM1L162L116
10064315 ON MCM1R162R116
10064315 ON SHIPPING
10064316 MS 00801-1778
10064316 MS SHIPPING
10064317 AZ CHM110439-1
10064317 AZ SHIPPING
10064318 TX 2607
10064318 TX SHIPPING
10064319 MO CHG8080
10064319 MO SHIPPING
10064322 CA W10001130
I want to write a sql query that only list on the order number that without SHIPPING, in this sample, the only one without SHIPPING would be 10064322.
I try to find in here but didn't find what I am looking for.
Thank for the help
SELECT DISTINCT [order]
FROM MYTABLE
WHERE [order] not in (SELECT [order]
FROM MYTABLE
WHERE [item id] = 'SHIPPING')
EDIT:
According to Aaron Bertrand's article (hat tip #TTeeple in the comments) the best performance for this problem (needing the distinct) is done as follows:
SELECT [order]
FROM MYTABLE
EXCEPT
SELECT [order]
FROM MYTABLE
WHERE [item id] = 'SHIPPING'
For the full article -> http://sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-join
One option is to use not exists:
select ordernumber
from yourtable y
where not exists (
select 1
from yourtable y2
where y.ordernumber = y2.ordernumber and y2.itemid = 'SHIPPING'
)
Use conditional aggregation:
select [order] from
table
group by [order]
having sum(case when [item id] = 'SHIPPING' then 1 else 0 end) = 0

How to get Count of Records in sql

My sql table structure is :
Order No. | Carton No | ... .& so on
D1 1
D1 2
D1 3
D1 4
D2 5
D2 6
I want to get the count of Carton No group By Order No . and the records included in the count.
like this -
OrderNo | Count | Carton No
D1 4 1,2,3,4
D2 2 5,6
Is it possible to get the desired result using sql query.
SELECT "Order No.",COUNT("Order No.")as Count ,
listagg("Carton No" , ',') within group (order by "Carton No") "Carton No"
FROM tableName
GROUP BY "Order No."
SQL Server
SELECT [Order No.],COUNT([Order No.])as Count ,
[Carton No]=STUFF((SELECT ','+[Carton No] FROM tableName WHERE [Order No.]=A.[Order No.]
FOR XML PATH('')) , 1 , 1 , '' )
FROM
tableName A
GROUP BY [Order No.]
The COUNT() function gets you the count, but the comma-delimited list is much more difficult. As far as ANSI standard SQL, no. What you're asking denormalizes the query results, therefore the standard SQL response is to do this in the application, not in SQL. It's a display issue.
Many RDBMSs do have vendor-specific aggregate functions that do this, however:
Oracle: wm_concat() and LISTAGG(). wm_concat() is older, but it was never considered a documented function.
MySQL: GROUP_CONCAT().
PostgreSQL: array_agg() and string_agg(). Older versions may not have both or either function.
MS SQL: This one is extremely difficult. You generally have to use STUFF() in combination with FOR XML PATH(''). However, this behavior is not a documented behavior, so should be considered deprecated. Prior to SQL Server 2005's introduction of the FOR XML PATH('') statement, I don't believe there was any good way to do this.
SQLite: GROUP_CONCAT().
DECLARE #MYTABLE TABLE(ID NVARCHAR(5),zone CHAR(1))
INSERT INTO #MYTABLE VALUES
('D1',1),('D1',2),('D1',3),
('D1',4),('D2',5),('D2',6)
SELECT t.ID,COUNT(ID) AS [Count]
,STUFF((SELECT '/'+ zone
FROM #MYTABLE
WHERE ID = t.ID
FOR XML PATH(''),TYPE).
value('.','NVARCHAR(MAX)'),1,1,'') AS Zones
FROM #MYTABLE t
GROUP BY t.ID