Crystal reports, selecting latest apearence of group in table - sql-server

I am new in this Crystal Reports thing and I have problem, since my coworker usually doing this stuff is sick at home I need to figure it out my self. I have 2 tables.
First is like this:
Article.ID Article.name Article.buyingprice
1 aa 2.00
2 bb 1.00
3 cc 3.50
4 dd 4.20
5 ee 2.00
And second is like this:
Income.ID Income.article Income.date Income.number Income.quantity
1 2 79100 P1 2.00
2 1 79100 P1 3.00
3 4 79101 P2 2.00
4 3 79101 P2 1.00
5 1 79101 P2 4.00
6 5 79101 P2 1.00
7 2 79103 P3 15.00
What I need is formula for selecting Income.quantity from the latest Income document. For example for article aa it will be 4.00 and for article bb it will be 15. Please save my job folks :)
Report is grouped by article.name.

For your solution you can make a group in Crystal report
Add group on ArticleId sort by ascending
Add One more group on IncomeId sort by descending
Now Suppress all Group headers and footer
open section expert , set formula below
Formula: if(previous({Command.Aritcle.ID}) = {Command.Aritcle.ID}) then true else false;

This Can Be Achieved in SQl server by using CTE
BEGIN TRAN
CREATE TABLE #Article (ID INT ,name NVARCHAR(20),buyingprice Decimal (15,2))
CREATE TABLE #Income (ID INT ,article INT,DATE nvarchar(50),number nvarchar(20),quantity Decimal (15,2))
insert into #Article
SELECT 1,'aa',2.00 union all
SELECT 2,'bb',1.00 union all
SELECT 3,'cc',3.50 union all
SELECT 4,'dd',4.20 union all
SELECT 5,'ee',2.00
insert into #Income
select 1,2,'79100','P1',2.00 union all
select 2,1,'79100','P1' ,3.00 union all
select 3,4,'79101','P2',2.00 union all
select 4,3,'79101','P2',1.00 union all
select 5,1,'79101','P2',4.00 union all
select 6,5,'79101','P2',1.00 union all
select 7,2,'79103','P3',15.00
go
with CTE as
( select A.ID,name,b.date, B.quantity,ROW_NUMBER() OVER(PARTITION BY a.ID,name ORDER BY a.ID,name ) AS Rn
FROM #Article A inner JOIN #Income B ON A.ID=B.article
)
SELECT a.ID,a.date,a.name, a.quantity
FROM CTE a
WHERE a.Rn= (SELECT MAX(rn) FROM cte b)
ROLLBACK TRAN

Related

Merge results from two tables through 1 common column

We have some warehouses which we do inventory on a regular basis.
I need to make a report (the goal is to use Microsoft PowerBi) to show the discrepancies between different inventories for the same warehouse (location), but the only common column is the warehouse number.
Product column is dynamically: it may appear on an inventory and not on another (and that is exactly what we need to know)
Each inventory is on a different table, like this:
TABLE A
LOCATION PRODUCTS QTY
WH 1 PRODUCT NO. 1 10
WH 1 PRODUCT NO. 2 100
WH 1 PRODUCT NO. 333 5
WH 2 PRODUCT NO. YYY 22
TABLE B
LOCATION PRODUCTS QTY
WH 1 PRODUCT NO. 1 10
WH 1 PRODUCT NO. 2 100
WH 1 PRODUCT NO. 333 5
WH 1 PRODUCT NO. XXX 77
WH 2 PRODUCT NO. YYY 45
WH 1 PRODUCT NO. YYY 555
WH 2 PRODUCT NO. 1 14
Expected output should be like this:
Location products QTY A QTY B
WH 1 PRODUCT NO. 1 10 10
WH 1 PRODUCT NO. 2 100 100
WH 1 PRODUCT NO. 333 5 5
WH 1 PRODUCT NO. XXX - 77
WH 1 PRODUCT NO. YYY - 555
WH 2 PRODUCT NO. 1 - 14
WH 2 PRODUCT NO. YYY 22 45
I´ve read about FULL OUTER JOIN and also PIVOT TABLES, but I was unable to fully understand and use them (and I´m also not sure they are the goal here).
SQL version is Microsoft SQL Server 2016 Standard
One option is a Union ALL in concert with a PIVOT or Conditional Aggregation
Example
Select *
From (
Select Location
,Products
,Qty
,Col = 'Qty A'
From Table A
Union All
Select Location
,Products
,Qty
,Col = 'Qty B'
From Table B
) src
Pivot (sum(Qty) for Col in ([Qty A],[Qty B] ) ) pvt
Isn't this a simple full join? Am I missing something? Pivot seems unnecessary here.
select isnull(A.location,B.location) location, isnull(A.products, B.products) products,
A.QTY A_QTY, B.QTY B_QTY
from tableA A
full outer join tableB B
on A.location = B.location
and A.products = B.products
A_QTY or B_QTY will be null if it's in one table but not the other.
Try this:
;with tableA (LOCATION, PRODUCTS, QTY)
as
(
select 'WH 1','PRODUCT NO. 1',10
union all
select 'WH 1','PRODUCT NO. 2',100
union all
select 'WH 1','PRODUCT NO. 333',5
union all
select 'WH 2','PRODUCT NO. YYY',22
)
, tableB (LOCATION, PRODUCTS, QTY)
as
(
select 'WH 1','PRODUCT NO. 1',10
union all
select 'WH 1','PRODUCT NO. 2',100
union all
select 'WH 1','PRODUCT NO. 333',5
union all
select 'WH 1','PRODUCT NO. XXX',77
union all
select 'WH 2','PRODUCT NO. YYY',45
union all
select 'WH 1','PRODUCT NO. YYY',555
union all
select 'WH 2','PRODUCT NO. 1',14
)
select
LOCATION
, PRODUCTS
, isnull(QtyA,0) [Qty A]
, isnull(QtyB,0) [Qty B]
from
(
select
LOCATION
, PRODUCTS
, QTY
, 'QtyA' ColumnQty
from tableA
union all
select
LOCATION
, PRODUCTS
, QTY
, 'QtyB' ColumnQty
from tableB
) source
pivot
(
sum(QTY) for ColumnQty in ([QtyA],[QtyB])
) pvt
I've tested it and it works as can be seen here.

Row data from a comma-delimited field used within a select query

I am trying to build a single select query that returns
a list of Product Type Description using Table1 that is not
in the ExcludedList of Table2.
I have the following tables and data in SQL Server 2008.
Table1(nProdType INT, sProdDesc VARCHAR)
nProdType SProdDesc
----------- --------------------
1 Pencils
2 Paper
3 Pens
4 Markers
5 Erasers
6 Crayons
7 HighLighters
8 Rulers
Table2(ClassID INT, ExcludeList VARCHAR)
ClassID ExcludedList
----------- --------------------
100 2,3,4,8
101 1,2,5,6,7,8
102 4,5,6,7
103 1,2,3,4,5,6,7,8
104 7
The query should return the following:
ClassID nProdType sProdDesc
-------- --------- --------------
100 1 Pencils
100 5 Erasers
100 6 Crayons
100 7 HighLighters
101 3 Pens
101 4 Markers
102 1 Pencils
102 2 Paper
102 3 Pens
102 8 Rulers
..and so on..
I know how to build (and of course there are plenty solutions in SO) a function to split the comma-delimited field but they return ALL the rows in the table and I want it to be per record (ClassID) so that I can query to see what's not in the ExcludedList. I am trying to not code this in C# or to use a RecordSet.
You can use a CSV Splitter for this. Here is the DelimitedSplit8K function by Jeff Moden.
;WITH CteDelimitted AS(
SELECT
t.ClassID,
nProdType = CAST(s.Item AS INT)
FROM Table2 t
CROSS APPLY dbo.DelimitedSplit8K(t.ExcludedList, ',') s
),
CteCross AS(
SELECT
t2.ClassID,
t1.nProdType,
t1.SprodDesc
FROM Table1 t1
CROSS JOIN(
SELECT DISTINCT ClassID FROM Table2
)t2
)
SELECT *
FROM CteCross c
WHERE NOT EXISTS(
SELECT 1
FROM CteDelimitted
WHERE
ClassID = c.ClassID
AND nProdType = c.nProdType
)
ORDER BY ClassID, nProdType
SQL Fiddle
Another approach using NOT IN:
WITH Cte AS(
SELECT
t2.ClassID,
t1.nProdType,
t1.SprodDesc
FROM Table1 t1
CROSS JOIN(
SELECT DISTINCT ClassID FROM Table2
)t2
)
SELECT *
FROM Cte c
WHERE c.nProdType NOT IN(
SELECT CAST(s.Item AS INT)
FROM Table2
CROSS APPLY dbo.DelimitedSplit8K(ExcludedList, ',') s
WHERE ClassID = c.ClassID
)
ORDER BY ClassID, nProdType
SQL Fiddle

T-SQL select rows by oldest date and unique category

I'm using Microsoft SQL. I have a table that contains information stored by two different categories and a date. For example:
ID Cat1 Cat2 Date/Time Data
1 1 A 11:00 456
2 1 B 11:01 789
3 1 A 11:01 123
4 2 A 11:05 987
5 2 B 11:06 654
6 1 A 11:06 321
I want to extract one line for each unique combination of Cat1 and Cat2 and I need the line with the oldest date. In the above I want ID = 1, 2, 4, and 5.
Thanks
Have a look at row_number() on MSDN.
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY date_time, id) rn
FROM mytable
) q
WHERE rn = 1
(run the code on SQL Fiddle)
Quassnoi's answer is fine, but I'm a bit uncomfortable with how it handles dups. It seems to return based on insertion order, but I'm not sure if even that can be guaranteed? (see these two fiddles for an example where the result changes based on insertion order: dup at the end, dup at the beginning)
Plus, I kinda like staying with old-school SQL when I can, so I would do it this way (see this fiddle for how it handles dups):
select *
from my_table t1
left join my_table t2
on t1.cat1 = t2.cat1
and t1.cat2 = t2.cat2
and t1.datetime > t2.datetime
where t2.datetime is null

Expand row results based on a value in column (with iterator)

Need help from you all in writing up this query. Running SQL 2005 Standard edition.
I have a basic query that gets a subset of records from a table where the record_Count is greater then 1.
SELECT *
FROM Table_Records
WHERE Record_Count > 1
This query gives me a result set of, say:
TableRecords_ID Record_Desc Record_Count
123 XYZ 3
456 PQR 2
The above query needs to be modified so that each record appears as many times as the Record_Count and has its iteration number with it, as a value. So the new query should return results as follows:
TableRecords_ID Record_Desc Record_Count Rec_Iteration
123 XYZ 3 1
123 XYZ 3 2
123 XYZ 3 3
456 PQR 2 1
456 PQR 2 2
Could anyone help we write this query up? appreciate the help.
Clarification: Rec_Iteration column is a sub representation of the Record_Count. Basically, since there are three Record_Count for XYZ description thus three rows were returned with the Rec_Iteration representing the Row one , two and three respectively.
You can use a recursive CTE for this query. Below I use a table variable #T instead of your table Table_Records.
declare #T table(TableRecords_ID int,Record_Desc varchar(3), Record_Count int)
insert into #T
select 123, 'XYZ', 3 union all
select 456, 'PQR', 2
;with cte as
(
select TableRecords_ID,
Record_Desc,
Record_Count,
1 as Rec_Iteration
from #T
where Record_Count > 1
union all
select TableRecords_ID,
Record_Desc,
Record_Count,
Rec_Iteration + 1
from cte
where Rec_Iteration < Record_Count
)
select TableRecords_ID,
Record_Desc,
Record_Count,
Rec_Iteration
from cte
order by TableRecords_ID,
Rec_Iteration

Select a distinct record, filtering is not working

Hello EVery I am new to SQl. query to result in the following records.
I have a table with records as
c1 c2 c3 c4 c5 c6
1 John 2.3.2010 12:09:54 4 7 99
2 mike 2.3.2010 13:09:59 8 6 88
3 ahmad 2.3.2010 13:09:59 1 9 19
4 Jim 23.3.2010 16:35:14 4 5 99
5 run 23.3.2010 12:09:54 3 8 12
I want to fecth only records.
i.e only 1 latest record per day. If both of them happen at the same time, sort by C1.so in 1&3 it should fetch 3.
3 ahmad 2.3.2010 14:09:59 1 9 19
4 Jim 23.3.2010 16:35:14 4 5 99
I have got a new problem in this.
If i filter the records based on conditions the last record is missing. I tried many ways but still it is failing. Here update_log is my table.
SELECT * FROM update_log t1
WHERE (t1.c3) =
(
SELECT MAX(t2.c3)
FROM update_log t2
WHERE DATEDIFF(dd,t2.c3, t1.c3) = 0
)
and t1.c3 > '02.03.2010' and t1.modified_at <= '22.03.2010'
ORDER BY t1.c3 ASC. But i am not able to retrieve the record
4 Jim 23.3.2010 16:35:14 4 5 99
I dont know this query results in only
3 ahmad 2.3.2010 14:09:59 1 9 19
The format of the column c3 is datetime. I am pumping the data into the column as
using $date = date("d.m.Y H:i",time()); -- simple date fetch of today.
Another query that i tried for the same purpose.
select * from (select convert(varchar(10), c3,104) as date, max(c3) as max_date, max(c1) as Nr from update_log group by convert(varchar(10), c3,104)) as t2 inner join update_log as t1 on (t2.max_date = t1.c3 and convert(varchar(10), c3,104) = date and t1.[c1]= Nr) WHERE t1.c3 >= '02.03.2010' and t1.c3 <= '16.04.2010' . I even tried this way..the same error last record is not coming..
Following steps should produce the results you are after
Find max c3 for every day.
Join the results with your original table, witholding only the max c1 values.
SQL Statement (Edited)
DECLARE #update_log TABLE (c1 INTEGER, c3 DATETIME)
INSERT INTO #update_log
SELECT 1, '3.2.2010 12:09:54'
UNION ALL SELECT 2, '3.2.2010 13:09:59'
UNION ALL SELECT 3, '3.2.2010 13:09:59'
UNION ALL SELECT 4, '3.23.2010 16:35:14'
UNION ALL SELECT 5, '3.23.2010 12:09:54'
SELECT c1 = MAX(l.c1), l.c3
FROM #update_log l
INNER JOIN (
SELECT c3_max = MAX(c3)
FROM #update_log
WHERE c3 > '3.2.2010 00:00:00'
AND c3 < '3.24.2010 00:00:00'
GROUP BY
CONVERT(VARCHAR(10), c3, 101)
) l_maxdate ON l_maxdate.c3_max = l.c3
GROUP BY
l.c3
Notes
You should read the FAQ regarding as to how this site operates. As has been mentioned, Stack Overflow is not intented to be used like one would use a newsreader where you ask follow-up questions after an answer has been given by creating a new answer.
You should edit your question for any additional information or use the comments. If the additional information is that much that it in effect changes the entire question, you should consider making a new question out of it.
That being said, enjoy SO.
Assuming c1 is unique, hopefully even the primary key. This also assumes the use of SQL Server 2008 for the DATE data type.
SELECT t1.*
FROM update_log t1
WHERE t1.c3 > '02.03.2010'
AND t1.modified_at <= '22.03.2010'
AND t1.c1 IN
( SELECT TOP 1 c1
FROM update_log t2
WHERE CAST(t1.c3 As DATE) = CAST(t2.c3 As DATE)
ORDER BY c3 DESC, c1 DESC
)
OK, Now i understood. actually i wrote the query for the same purpose this way.
select * from #temp
select * from
(select max(c1) as nr from
(select convert(varchar(10), c3,104) as date, max(c3) as max_date
from #temp where
convert(varchar(10),c3,104) >= '02.02.2010' and
convert(varchar(10),c3,104) <= '23.02.2010'
group by convert(varchar(10), c3,104))
as t2 inner join #temp as t1 on (t2.max_date = t1.c3 and
convert(varchar(10), c3,104) = date)
group by convert(varchar(10),max_date,104))
as t3 inner join #temp as t4 on (t3.nr = t4.c1 )
If i change these 2 lines to c3 >= '02.02.2010' and
c3 <= '24.02.2010'. It is working fine. but the query that i have posted is not able to filter the records properly based on dates.
I want to know where i went to wrong to enhance my knoweldge rather than just copying ur query:-)

Resources