How to add headers in MySQL above sets of data - mysql

Headers might be the wrong word but if I have a table of shifts for a job and a table of customers I'm trying to figure out how to select a row displaying the customer information in between customers.
[Shift Table]
shift_id, customer_id, date
[Shift_Needs_Workers]
id, shift_id, people_id (nullable = true)
[Customers]
customer_id, customer_name
Customers can have multiple shifts and Shifts can have multiple workers needed
I'm wanting to run a SELECT statement that can output
Customer A
Shift 1, Worker 1
Shift 1, Worker 2
Shift 2, Worker 1
Shift 2, Worker 2
Shift 2, Worker 3
Customer B
Shift 1, Worker 1
Shift 2, Worker 2
etc
I looked into with rollup but that seems to need something to group by and I'm the opposite I want all the rows but then an extra one. I looked into Union but it looked like it was one additional query or multiple separate queries and I want to "union" in the middle of my queries where the customer_id changes.
Any help or other links that might help would be awesome.

You could build your reports with jasper reports. You would create one main report for the customers and a subreport for the shift information.
If you want to do it in one statement, you would first have to generate a structure like this
CustomerA, null, null, 0
CustomerA, Shift1, Worker1, 1
CustomerA, Shift1, Worker2, 1
CustomerB, null, null, 0
The last column is the level of the information.
After you have this structure, which you can easily generate using unions and joins
you can generate an output column with a case or if then else
case levelNr when 0 then customer_name else concat(shift_id, ' ', worker_id) end

Related

How to create a particular SSRS Expression for this example?

if some could help me to i will be very grateful.
This can be done by separating the table into 2 tables but I want to do it with a formula if possible.
We have the following report:
We need to get the data from the table and add them into the totals on line 2 (those are textbox, not a table)
"TOTAL ID" and "TOTAL AMOUNT" is easy to do using the expressions:
=CountDistinct(Fields!id.Value, "opp_win_lose") (opp_win_lose = dataset) (we have 3 datasets so we need to put to which dataset it belongs)
=ReportItems!Textbox44.Value
The problem gets at "TOTAL ID STATUS PENDING" and "TOTAL AMOUNT STATUS PENDING"
I need to create the expression with the condition that status = Pending (or Running) that is a group, so we have
TOTAL ID STATUS PENDING = 3
TOTAL AMOUNT STATUS PENDING = 100
Thanks.
Nothing worked, try a few expressions.
It sounds like you just need to add a condition to the COUNT and SUM fields for the Pending ones.
=CountDistinct(IIF(Fields!STATUS.Value = "Pending", Fields!id.Value, NOTHING), "opp_win_lose")
=SUM(IIF(Fields!STATUS.Value = "Pending", Fields!AMOUNT.Value, 0), "opp_win_lose")
It looks like the summary data is from the same table. It might have been easier to use a table for your summary. Group the table on 1 (the number) so there's only one total line. Then you don't need the name the dataset.

Query for showing stock as of given date in the past

I am developing software for warehouse management.
I got three tables: itemstock, documents, doc_pcs
itemstock fields (not all of them are shown):
rfid_no (which is unique and primary key)
item_name
status
documents fields:
id
doc_date
doc_type
doc_pcs fields:
id
id_doc | these two are primary key
pos | (id_doc is connected to documents.id)
rfid_no (from itemstock.rfid_no)
First table is for collecting records of items, nothing is ever erased from this table, there's just status change when something happens with particular item (goes out to client, comes back etc).
Documents and doc_pcs tables store document data.
doc_type is for marking whether items on document were going in or out of the warehouse.
The problem is:
I need to create query that shows all the stock as of given date.
In other words:
It should show all items from today's itemstock with status=6 ("stored") MINUS records with rfid_no that have matches in doc_pcs related to documents dated between today and a given date and with doc_type="out" PLUS records with rfid_no that have matches in doc_pcs related to documents dated between today and a given date and with doc_type="in"
Was searching for any clue here and there for few days now and I could not find anything that will lead me to any solution. I will be gratefull for any help!
Sample data:
itemstock (as of today):
00300D0909DA, "tshirt", 6
00300D0909DB, "apron", 6
00300D0909DC, "tshirt", 6
00300D0909DD, "trousers", 6
00300D0909DE, "tshirt", 1
00300D0909DF, "trousers", 1
00300D0909E0, "trousers", 6
documents:
0,2015-08-01,"in"
1,2015-08-02,"in"
2,2015-08-03,"out"
3,2015-08-04,"in"
4,2015-08-05,"out"
5,2015-08-06,"in"
doc_pcs:
0, 1, 00300D0909DA
0, 2, 00300D0909DE
1, 1, 00300D0909DF
1, 2, 00300D0909DD
2, 1, 00300D0909DE
3, 1, 00300D0909DB
4, 1, 00300D0909DF
5, 1, 00300D0909DC
5, 2, 00300D0909E0
query results for given doc_date=2015-08-04 including fields rfid_no and item_name should be:
00300D0909DA, "tshirt"
00300D0909DB, "apron"
00300D0909DD, "trousers"
00300D0909DF, "trousers"
EDIT:
I've managed to make following query but it executes endlessly hence I believe something is wrong:
SELECT DISTINCT c.rfid_no
FROM itemstock c LEFT JOIN doc_pcs d
ON c.rfid_no=d.rfid_no
WHERE c.status=6
OR
(d.id IN
(SELECT dk.id
FROM documents dk
WHERE DATE(dk.doc_date)>='2015-08-04'
AND dk.doc_type="out")
AND
d.id NOT IN
(SELECT dk.id
FROM documents dk
WHERE DATE(dk.doc_date)>='2015-08-04'
AND dk.doc_type="in"))
It seems like you could either go from today's values and work backwards or you could start from 'day 0' and work forwards. By storing the stock count as of 'today' you are denormalizing the data so I'd opt for the second approach (and maybe you could save yourself a table).
Assume that as of 'day 0' all stock is empty. To get the stock count as of a given date you would (p-query):
select sum((select count inbound where date <= inventory_date) - (select count outbound where date <= inventory_date))

Can SQL query do this?

I have a table "audit" with a "description" column, a "record_id" column and a "record_date" column. I want to select only those records where the description matches one of two possible strings (say, LIKE "NEW%" OR LIKE "ARCH%") where the record_id in each of those two matches each other. I then need to calculate the difference in days between the record_date of each other.
For instance, my table may contain:
id description record_id record_date
1 New Sub 1000 04/14/13
2 Mod 1000 04/14/13
3 Archived 1000 04/15/13
4 New Sub 1001 04/13/13
I would want to select only rows 1 and 3 and then calculate the number of days between 4/15 and 4/14 to determine how long it took to go from New to Archived for that record (1000). Both a New and an Archived entry must be present for any record for it to be counted (I don't care about ones that haven't been archived). Does this make sense and is it possible to calculate this in a SQL query? I don't know much beyond basic SQL.
I am using MySQL Workbench to do this.
The following is untested, but it should work asuming that any given record_id can only show up once with "New Sub" and "Archived"
select n.id as new_id
,a.id as archive_id
,record_id
,n.record_date as new_date
,a.record_date as archive_date
,DateDiff(a.record_date, n.record_date) as days_between
from audit n
join audit a using(record_id)
where n.description = 'New Sub'
and a.description = 'Archieved';
I changed from OR to AND, because I thought you wanted only the nr of days between records that was actually archived.
My test was in SQL Server so the syntax might need to be tweaked slightly for your (especially the DATEDIFF function) but you can select from the same table twice, one side grabbing the 'new' and one grabbing the 'archived' then linking them by record_id...
SELECT
newsub.id,
newsub.description,
newsub.record_date,
arc.id,
arc.description,
arc.record_date,
DATEDIFF(day, newsub.record_date, arc.record_date) AS DaysBetween
FROM
foo1 arc
, foo1 newsub
WHERE
(newsub.description LIKE 'NEW%')
AND
(arc.description LIKE 'ARC%')
AND
(newsub.record_id = arc.record_id)

Formatting a MySQL Query result

I've currently got a table as follows,
Column Type
time datetime
ticket int(20)
agentid int(20)
ExitStatus varchar(50)
Queue varchar(50)
I want to write a query which will break this down by week, providing a column with a count for each ExitStatus. So far I have this,
SELECT ExitStatus,COUNT(ExitStatus) AS ExitStatusCount, DAY(time) AS TimePeriod
FROM `table`
GROUP BY TimePeriod, ExitStatus
Output:
ExitStatus ExitStatusCount TimePeriod
NoAgentID 1 4
Success 3 4
NoAgentID 1 5
Success 5 5
I want to change this so it returns results in this format:
week | COUNT(NoAgentID) | COUNT(Success) |
Ideally, I'd like the columns to be dynamic as other ExitStatus values may be possible.
This information will be formatted and presented to end user in a table on a page. Can this be done in SQL or should I reformat it in PHP?
There is no "general" solution to your problem (called cross tabulation) that can be achieved with a single query. There are four possible solutions:
Hardcode all possible ExitStatus'es in your query and keep it updated as you see the need for more and more of them. For example:
SELECT
Day(Time) AS TimePeriod,
SUM(IF(ExitStatus = 'NoAgentID', 1, 0)) AS NoAgentID,
SUM(IF(ExitStatus = 'Success', 1, 0)) AS Success
-- #TODO: Add others here when/if needed
FROM table
WHERE ...
GROUP BY TimePeriod
Do a first query to get all possible ExitStatus'es and then create your final query from your high-level programming language based on those results.
Use a special module for cross tabulation on your high-level programming language. For Perl, you have the SQLCrossTab module but I couldn't find one for PHP
Add another layer to your application by using OLAP (multi-dimensional views of your data) like Pentaho and then querying that layer instead of your original data
You can read a lot more about these solutions and an overall discussion of the subject
This is one way; you can use SUM() to count the number of items a particular condition is true. At the end you just group by the time as per normal.
SELECT DAY(time) AS TimePeriod,
SUM('NoAgentID' = exitStatus) AS NoAgentID,
SUM('Success' = exitStatus) AS Success, ...
FROM `table`
GROUP BY TimePeriod
Output:
4 1 3
5 1 5
The columns here are not dynamic though, which means you have to add conditions as you go along.
SELECT week(time) AS week,
SUM(ExitStatus = 'NoAgentID') AS 'COUNT(NoAgentID)',
SUM(ExitStatus = 'Success') AS 'COUNT(Success)'
FROM `table`
GROUP BY week
I'm making some guesses about how ExitStatus column works. Also, there are many ways of interpretting "week", such as week of year, of month, or quarter, ... You will need to put the appropriate function there.

Complex MySQL COUNT query

Evening folks,
I have a complex MySQL COUNT query I am trying to perform and am looking for the best way to do it.
In our system, we have References. Each Reference can have many (or no) Income Sources, each of which can be validated or not (status). We have a Reference table and an Income table - each row in the Income table points back to Reference with reference_id
On our 'Awaiting' page (the screen that shows each Income that is yet to be validated), we show it grouped by Reference. So you may, for example, see Mr John Smith has 3 Income Sources.
We want it to show something like "2 of 3 Validated" beside each row
My problem is writing the query that figures this out!
What I have been trying to do is this, using a combination of PHP and MySQL to bridge the gap where SQL (or my knowledge) falls short:
First, select a COUNT of the number of incomes associated with each reference:
SELECT `reference_id`, COUNT(status) AS status_count
FROM (`income`)
WHERE `income`.`status` = 0
GROUP BY `reference_id`
Next, having used PHP to generate a WHERE IN clause, proceed to COUNT the number of confirmed references from these:
SELECT `reference_id`, COUNT(status) AS status_count
FROM (`income`)
WHERE `reference_id` IN ('8469', '78969', '126613', ..... etc
AND status = 1
GROUP BY `reference_id`
However this doesn't work. It returns 0 rows.
Any way to achieve what I'm after?
Thanks!
In MySQL, you can SUM() on a boolean expression to get a count of the rows where that expression is true. You can do this because MySQL treats true as the integer 1 and false as the integer 0.
SELECT `reference_id`,
SUM(`status` = 1) AS `validated_count`,
COUNT(*) AS `total_count`
FROM `income`
GROUP BY `reference_id`